home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 October: Mac OS SDK / Dev.CD Oct 96 SDK / Dev.CD Oct 96 SDK2.toast / Development Kits (Disc 2) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc Source Code / Storage / Bento / CMDraft.cpp < prev    next >
Encoding:
Text File  |  1996-04-22  |  158.7 KB  |  5,249 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        CMDraft.cpp
  3.  
  4.     Contains:    Implementation for CMDraft class.
  5.  
  6.     Owned by:    Vincent Lo
  7.  
  8.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <8>     3/22/96    CC        1330388: Support direct clone between
  13.                                     document drafts.
  14.          <7>     3/15/96    DM        1295410: create list iterators on stack
  15.                                     (avoid mem thrash during purge)
  16.                                     1292140: throw when persistent object has
  17.                                     no storage unit getting draft or session
  18.          <6>     3/15/96    CC        1316917: Don't remove valuable data
  19.                                     interchange properties when cloning with
  20.                                     kODCloneAll.
  21.          <5>     3/13/96    VL        1305064: Removed class purging code as it
  22.                                     is done by SOM now.
  23.          <4>      3/8/96    EL        1308013: If loading of editor fails,
  24.                                     replace by NoPart. Code reviewed by DM.
  25.          <3>     1/16/96    VL        1170098: Emptied out PartDeleted and
  26.                                     PartInstantiated as they are no longer
  27.                                     needed.
  28.          <2>     1/15/96    TJ        Cleaned Up
  29.        <125>    10/24/95    TJ        Changed string to corbastring
  30.        <124>    10/24/95    jpa        1293441: DM/VL: Bento memory reserve &
  31.                                     fatal container err & don't throw in
  32.                                     Release.
  33.        <123>    10/20/95    VL        1293256: Changed
  34.                                     kODErrBentoInvalidVersionList to
  35.                                     kODErrDraftDoesNotExist.
  36.        <122>    10/19/95    EL        1292685: After purging we may get a
  37.                                     different storage unit for the same
  38.                                     CMObject.
  39.        <121>    10/17/95    jpa        1289153: CreatePart, AcquirePart,
  40.                                     AcquireFrame handle failure gracefully.
  41.        <120>    10/13/95    EL        1287340: Use standard ISO prefix
  42.        <119>     10/8/95    TJ        Fixes Recomended by Refball
  43.        <118>     10/5/95    CC        1286180: Added CloneCompanionObject method.
  44.                                     1286180: Clone: Call CloneCompanionObject
  45.                                     if clone kind is kODCloneAll.
  46.        <117>     10/3/95    TJ        Changes done by RefBall Team
  47.        <116>     9/29/95    TJ        Made Changes for MAC SOM
  48.        <115>     9/14/95    VL        1283566: Fixed Clone so that CloneFromLink
  49.                                     would also skip links (i.e., return 0 as
  50.                                     the id).
  51.        <114>     9/11/95    VL        1283326: CreateFrame now takes ODObjectType
  52.                                     instead of ODType. 1283157: Fixed memory
  53.                                     Leak in CMDraft::ConstructRealPart.
  54.        <113>      9/8/95    VL        1276955: Make sure draft is not read-only
  55.                                     before writing out preferred kind.
  56.        <112>      9/8/95    TÇ        1281096 FB2:Many constants in ODTypesB
  57.                                     without kOD prefix!
  58.        <111>      9/1/95    CC        1273646, 1279220:  Support kODCloneToFile.
  59.        <110>     8/29/95    VL        1279830, 1279074: THROW_IF_NULL after new
  60.                                     on SOM objects. 1279505: Catches exceptions
  61.                                     returned from ReleaseAll.
  62.        <109>     8/26/95    TÇ        1270499Two editors which support same kind
  63.                                     binding problem
  64.        <108>     8/25/95    JBS        1263078 FB: fix part editor swapping
  65.        <107>     8/24/95    CC        1251959: BeginClone must clean up before
  66.                                     returning an error.
  67.        <106>     8/24/95    EL        1274602: cmObject not released resulting in
  68.                                     wrong internal Bento ref count.
  69.        <105>     8/22/95    VL        1277720, 1278310: Cleaned up error code in
  70.                                     Release/RemoveStorageUnit.
  71.        <104>     8/21/95    VL        1278330, 1278315: Error code cleanup.
  72.        <103>     8/21/95    VL        1277291: Use GetOriginalCloneKind from
  73.                                     StorUtil. 1258660: Rewrote exception
  74.                                     handling for CreateFrame to ensure that the
  75.                                     correct exception are propogated.
  76.        <102>     8/17/95    CC        1277781: CheckPartAction: Check size of
  77.                                     storage unit type before comparing strings;
  78.                                     check for invalid part ID returned by
  79.                                     ODGetStrongSURefProp.
  80.        <101>     8/16/95    EL        Disable ODDebug_CloningAnnotations
  81.        <100>     8/16/95    NP        1274946: ErrorDef.idl problems. Add include
  82.                                     file. 1277286: CMDraft: ConstructRealPart
  83.                                     gropes ev->_major when it doesn't mean to.
  84.         <99>     8/16/95    VL        1266007: IsValidDraftKey returns kODFalse
  85.                                     for kODNULLKey.
  86.         <98>     8/15/95    CC        1274794, 1273863: CopyProperties: Focus to
  87.                                     property (don't assume already focused).
  88.                                     CopyDraftAnnotations: Always copy the
  89.                                     storage unit type property.
  90.         <97>     8/12/95    TÇ        1276812 Need to use TempObjs and TempRefs
  91.                                     for exception safety and to avoid TRY
  92.                                     blocks, 1276807 Opt./Bug: use StdTypIO
  93.                                     routines for portable streaming & smaller
  94.                                     footprint, 1276806 Optimization: use
  95.                                     kODFalse instead of kODTrue in comparisons
  96.         <96>      8/3/95    RR        #1257260: Collapse B classes. Remove
  97.                                     somInit methods. Don't call IsInitialized
  98.                                     or SubclassResponsibility
  99.         <95>     7/26/95    VL        1270320: Dispose of valueName in
  100.                                     CopyProperty.
  101.         <94>     7/21/95    VL        1270320: Freeing internal field. Disposed
  102.                                     ba._buffer of ID.
  103.         <93>     7/20/95    CC        1268790: Clone: Make sure original ID is
  104.                                     still valid before substituting!
  105.         <92>      7/3/95    VL        1255736: Every instantiated persistent
  106.                                     object has the object type correctly set.
  107.         <91>     6/29/95    VL        1242642: Release DraftProperties in
  108.                                     DeleteCollections. Release SU before
  109.                                     removing it.
  110.         <90>     6/23/95    JBS        1261323 Draft::CreateFrame: add isSubframe
  111.                                     param, remove isRoot
  112.         <89>     6/19/95    VL        1170098: Added code to count part instances
  113.                                     (PartInstantiated, PartDeleted,
  114.                                     PurgeClasses). Code for the actual
  115.                                     unloading of the libraries is commented out
  116.                                     now. Added DeleteRealPart.
  117.         <88>     6/16/95    VL        1244940: Made Externalize which triggers
  118.                                     promise resolution work.
  119.         <87>     6/14/95    VL        1251227: Delete the collections and their
  120.                                     objects in somUninit.
  121.         <86>     6/13/95    VL        1241352: Moved PreserveFocus to DrafPriv.
  122.         <85>     6/12/95    CC        1252059: BeginClone: Allow clone to link
  123.                                     when clone from link is in progress.
  124.         <84>     6/10/95    VL        1255300: Updated CopyDraftAnnotations for
  125.                                     cloning annotations and metadata.
  126.         <83>      6/7/95    CC        1255762: EndClone() now uses destFrame
  127.                                     passed to BeginClone().
  128.                                     CheckClonedObject, ContainingPartInClone,
  129.                                     CheckPartAction: Changed kODFrame to
  130.                                     kODFrameObject.
  131.                                     CheckClonedObject: Changed kODPart to
  132.                                     kODPartObject.
  133.                                     ContainingPartInClone: Fixed refcount
  134.                                     problem.
  135.         <82>      6/2/95    CC        1255476: CreateVersion, et. al. : release
  136.                                     document acquired for debug string.
  137.                                     1255476: ContainingPartInClone: Release
  138.                                     acquired parts and frames.
  139.                                     1255474: AcquireDocument restored to
  140.                                     GetDocument.
  141.                                     1255474: GetPersistentObject restored to
  142.                                     AcquirePersistentObject.
  143.                                     1255474: AcquireStorageUnitType restored to
  144.                                     GetStorageUnitType.
  145.         <81>      6/1/95    jpa        Handle errs thrown from ODNewObject.
  146.                                     [1242839]
  147.         <80>     5/26/95    VL        1251403: Multithreading naming support.
  148.         <79>     5/25/95    jpa        Fixed usage of ODDebug. [1253321]
  149.         <78>     5/22/95    CC        1242879: Added IsValidID.
  150.         <77>     5/22/95    VL        1246940: Preserve focus during Clone.
  151.         <76>     5/19/95    VL        1250574: Added check for kODNULLID in Get
  152.                                     methods.
  153.         <75>     5/18/95    CC        1238898: Add destFrame argument to
  154.                                     BeginClone call; added fDestFrame field.
  155.         <74>     5/17/95    VL        1170098: Added ConstructRealPart and
  156.                                     ReleaseRealPart.
  157.         <73>     5/17/95    RR        #1250135/1250137/1250143 Getters increment
  158.                                     refcount
  159.         <72>      5/3/95    CC        Split file into two segments to avoid
  160.                                     16-bit PC-relative offset problems on 68K.
  161.         <71>      5/2/95    CC        1207493: Detect embedding part within
  162.                                     itself.
  163.                                     New methods: ContainingPartInClone and
  164.                                     CheckClonedObject.
  165.                                     New fields: fAnyFrameCloned and
  166.                                     fRootPartCloned.
  167.                                     New static variables: sIntermediateDraft,
  168.                                     sSUTypeBuffer, and sRootPartIDToIgnore.
  169.                                     New static functions: CheckPartAction,
  170.                                     CopyDraftAnnotations, CopyProperty,
  171.                                     GetStorageUnitType, RootPartID.
  172.                                     1245718: StrongClone: Call
  173.                                     CopyDraftAnnotations.
  174.                                     1245706: CreatePart creates
  175.                                     kODPropPreferredKind property, not
  176.                                     kODPropPart.
  177.         <70>      5/2/95    VL        1211972: RemoveFrame does not dirty draft
  178.                                     if frame is non-persistent. 1243122: Use
  179.                                     kODErrValueIndexOutOfRange. 1221370:
  180.                                     AcquirePersistentObject works on read-only
  181.                                     draft.
  182.         <69>      5/2/95    EL        1234685: Container manager does not like
  183.                                     value created but not written to, so always
  184.                                     write something after CMNewValue.
  185.         <68>     4/25/95    DM        1172791: Replace AEHashTable with
  186.                                     OpenHashTable
  187.         <67>     4/25/95    VL        1210982: Removed 5$.
  188.         <66>     4/25/95    CC        1242555: CreateLinkSource, CreateLink,
  189.                                     Clone, AbortClone: Removed $5 from comment.
  190.         <65>     4/10/95    VL        1230350: Release Part before trying to
  191.                                     remove it.
  192.         <64>      4/7/95    EL        1226127: make sure code works when
  193.                                     TestFlushContainer is false.
  194.         <63>     3/31/95    TÇ        1223505 BB: Opening and creating documents
  195.                                     on read only media.  Fixed Creation of
  196.                                     Non-persistent frames on readonly drafts.
  197.         <62>     3/24/95    EL        1209355: Abort would remove changes in
  198.                                     version list rather than reinitialize it.
  199.                                     Cut down on version list externalization.
  200.         <61>     3/23/95    VL        1228003: Added debug code for versionlist.
  201.                                     1230371: Check before calling
  202.                                     IDList::Remove.
  203.         <60>     3/17/95    CC        1194656: SetOriginalDraft must check for
  204.                                     existence of property and value before
  205.                                     adding.
  206.         <59>     3/13/95    VL        1226094: Added error handling in CreateSU
  207.                                     to handle the case when any invalid ID is
  208.                                     passed in.
  209.         <58>     3/10/95    VL        1222416: Write out 0 at the end of
  210.                                     persistent object ISOString.
  211.         <57>      3/9/95    VL        1225504: Use GetTargetDocument to prevent
  212.                                     ref-counting problem.
  213.         <56>      3/7/95    CC        1224121: ODPart::CreateLink()  and
  214.                                     ODLinkManager::CreateLink() return an
  215.                                     ODLinkSource object.
  216.         <55>      3/6/95    EL        1182275: Replace SetDraftPropertyObject by
  217.                                     CMKeepObject.
  218.         <54>     2/28/95    VL        1194656: Check for existence before adding
  219.                                     property or value.
  220.         <53>     2/21/95    EL        1182275: Do not externalize object if it
  221.                                     was garbage collected. Tell embedded
  222.                                     container about the draft property object.
  223.         <52>     2/21/95    eeh        1222416: add 1 to len in
  224.                                     GetPersistentObjectID
  225.         <51>     2/17/95    VL        1220231: CreateFrame now calls
  226.                                     InitFrameNonPersistent.
  227.         <50>     2/15/95    EL        1182275: Set embedded container to no merge
  228.                                     if draft is created. 1158620: Lazy open
  229.                                     would avoid reopening of embedded container
  230.                                     when document is closed.
  231.         <49>     2/10/95    VL        1205627: Use TargetContainer in
  232.                                     CreateVersion.
  233.         <48>      2/6/95    TJ        Sorry, the last comment should be touched
  234.                                     copy right date.
  235.         <47>      2/6/95    TJ        Updated Check in Date.
  236.         <46>      2/3/95    VL        1216535: Implemented storage support for
  237.                                     non-persistent frames.
  238.         <45>     1/18/95    VL        1193559: Added new 2
  239.                                     methods(AcquirePersistentObject and
  240.                                     GetPersistentObjectID). Renamed
  241.                                     AcquirePersistentObject to
  242.                                     RetrievePersistentObject. Removed
  243.                                     GetPersistentLinkID and AcquireLinkID.
  244.         <44>     1/11/95    VL        1185688: Reverted one of the changes in
  245.                                     ExternalizeCollections to fix a refcounting
  246.                                     problem.
  247.         <43>     1/11/95    VL        1185688: Made storage more robust in terms
  248.                                     of error handling. Also did some code
  249.                                     review cleanup.
  250.         <42>    12/20/94    VL        1195012: Make Storage calls be
  251.                                     marshallable.
  252.         <41>    12/16/94    CC        1203516 Modified CreateLinkSource to use
  253.                                     SetLink() and SetLinkSource() methods,
  254.                                     modified CreateLink().
  255.         <40>    12/15/94    CC        1193569 CreateLinkSpec() takes ODByteArray
  256.                                     parameter.
  257.                                     1197221 AcquireLink() - added SOM_CATCH;
  258.                                     changed call to ODPart::CreateLink() to
  259.                                     pass byte array.
  260.         <39>     11/1/94    CC        1190911, 1192030, 1196908 - Clone reuses
  261.                                     same objects if moved within same draft;
  262.                                     Clone while fulfilling promises won't
  263.                                     recopy already cloned objects.
  264.         <38>     11/1/94    VL        1151339: Preparation for MergeContainer.
  265.         <37>    10/19/94    VL        1155857: Added ODDebug_Drafts to debug
  266.                                     "Cannot create more than 10 drafts"
  267.                                     problem.
  268.         <36>    10/12/94    VL        (JPA) Added debugstrs for frames.
  269.         <35>     10/4/94    CC        1190858 - Added ReleaseLinkSource().
  270.         <34>     9/29/94    RA        1189812: Mods for 68K build.
  271.         <33>     9/23/94    VL        1184272: ContainerID is now a sequence of
  272.                                     octets. This affects EmbeddedContainers
  273.                                     also.
  274.         <32>     9/23/94    CC        1187509 - Added somPrintfs for debugging
  275.                                     clone operations.
  276.         <31>     9/16/94    CC        1186957 - Fix to clone newly created links
  277.                                     correctly (added AcquireLinkSourceFromLink and
  278.                                     AcquireLinkFromLinkSource).
  279.         <30>     9/15/94    CC        1186776 - Enforce correct link behavior
  280.                                     during clone operations.
  281.                                     1160117 - Strip links when cloning into a
  282.                                     link.
  283.                                     1186657 - Correct ref count on object
  284.                                     returned by CreateLinkSource().
  285.                                     1153940 - Clone must support new clone kind
  286.                                     constants.
  287.         <29>      9/9/94    CG        #1183531: ConstructPart instantiates a
  288.                                     PartWrapper which in turn creates a part.
  289.         <28>      9/6/94    VL        1184177: Removed GetName and SetName.
  290.         <27>      9/5/94    VL        1184871: Used Renew to remove dependency on
  291.                                     default heap.
  292.         <26>     8/31/94    TÇ        #1183129, #1183116, #1183119, #1183111:
  293.                                     Lots of ErrorCode cleanup.
  294.         <25>     8/31/94    VL        1106013: Fixed GetName to return kODNULL if
  295.                                     the draft does not have a name.
  296.         <24>     8/26/94    VL        1183174: Added destDraft to BeginClone and
  297.                                     added toID to Clone.
  298.         <23>     8/19/94    TÇ        #1181622 Fix Written to Owned & name &
  299.                                     reference to ASLM Build
  300.         <22>     8/17/94    CG        #1181487: Instantiating parts by name
  301.                                     again!
  302.         <21>     8/16/94    TÇ        #1180922  Remove more obsolete types from
  303.                                     StdTypes.idl.  Localized kODStorageUnit to
  304.                                     this file.
  305.         <20>     8/16/94    VL        1143605: Added CloneInto.
  306.         <19>     8/15/94    VL        #???: Added frameType parameter to
  307.                                     CreateFrame.
  308.         <18>     8/13/94    TÇ        #1180814 Added support for ODPartWrapper
  309.                                     API
  310.         <17>     8/12/94    JBS        1179919: add biasCanvas param to
  311.                                     Draft::CreateFrame()
  312.         <16>     8/11/94    CC        Added implementation of
  313.                                     CreateLinkIterator() and
  314.                                     CreateLinkSourceIterator() methods.
  315.         <15>     8/10/94    JBS        1179919: coordinate system bias changes
  316.         <14>      8/4/94    eeh        bug 1179054: fix kODPartPartsBin
  317.         <13>      8/3/94    VL        1153123: Storage to ODStor.
  318.         <12>     7/28/94    TÇ        Create Clock statically
  319.         <11>     7/27/94    CC        Removed static functions IsMyProcess() and
  320.                                     IsRunningProcess(); changed AcquireLink()
  321.                                     method to use new ODLinkSpec methods.
  322.         <10>     7/26/94    VL        Got rid of MacStorageUnit and
  323.                                     MacDragAndDropStorageUnit.
  324.          <9>     7/26/94    eeh        hack in PartsBin and EditorSetup for static
  325.                                     build
  326.          <8>     7/21/94    VL        Removed ASLM BUILD.
  327.          <7>     7/19/94    CC        Create DragText statically.
  328.          <6>     7/18/94    TÇ        moved refcounting fixes to PstObj.cpp
  329.          <5>     7/18/94    TÇ        fixed another refcount problem
  330.          <4>     7/17/94    TÇ        fixed ReleasePersistentObject to release
  331.                                     the storageUnit of a persistentObject
  332.          <3>     7/14/94    eeh        Apple module name -> AppleTestDraw
  333.          <2>     7/12/94    VL        Added code to Create DrawPart statically.
  334.          <1>      7/5/94    VL        first checked in
  335.         -----------------------------------------------------------------------
  336.         <10>      6/1/94    CG        Changed to use public binding object.
  337.          <9>     5/27/94    jpa        Use ODNewObject to avoid ASLM dependency,
  338.                                     to support new exception scheme [1165267]
  339.          <8>      5/9/94    MB        #1162181: Changes necessary to install MMM.
  340.          <7>      4/6/94    JBS        1155480
  341.          <6>     3/28/94    TÇ        #1145834.  Remove PrtType.h & .cpp from the
  342.                                     project.  Noted a few places where there is
  343.                                     code which is only needed by the static
  344.                                     build.
  345.          <5>     3/28/94    CG        1153547: Changed XMPSessn.h to XMPSessM.h
  346.          <4>     3/27/94    TÇ        localized use of kXMPPropRootSU
  347.          <3>     3/25/94    CC        Change name of included file to
  348.                                     "LinkMgrM.h". (1153348)
  349.          <2>     3/25/94    MB        Symantec ASLM fixes. #1150864
  350.          <1>     3/24/94    VL        first checked in
  351.          <7>     3/18/94    CC        CMRegisterType(): Changed kXMPAppleTEXT
  352.                                     argument to kXMPISOStr. (1151636)
  353.          <6>     3/15/94    MB        Changes to support SCpp/ASLM builds,
  354.                                     #1150864.
  355.          <5>     3/14/94    CC        Added internal methods FixReusedLinks() and
  356.                                     ReferencedStorageUnitCloned(); Revised
  357.                                     EndClone(), PrepareLinksForClone().
  358.                                     (1149492)
  359.          <4>     2/22/94    VL        THROW -> THROW_IF_ERROR.
  360.          <3>     2/18/94    VL        #1142972, #1144024: Added
  361.                                     GetDragDropStorageUnit to enable importing
  362.                                     data from a foreign source (e.g. the
  363.                                     Finder).
  364.          <2>     2/17/94    CC        Bug #1142584 - GetOriginalCloneKind returns
  365.                                     kXMPCloneCopy by default in case content
  366.                                     was put directly onto the clipboard without
  367.                                     cloning.
  368.        <106>      2/8/94    VL        Corrected capitalization of include files
  369.                                     and used <> for Toolbox headers.
  370.        <105>      2/8/94    VL        Use new exception macros.
  371.        <104>      2/4/94    VL        Session.h -> XMPSessn.h.
  372.        <103>      2/4/94    VL        More code cleanup.
  373.        <102>      2/4/94    VL        Moved to PPC Header and began code cleanup.
  374.                                     (Added itoa to replace NumToString. Got rid
  375.                                     of some warnings.)
  376.        <101>      2/3/94    CG        System Session break out.
  377.        <100>      2/2/94    VL        Made Hash Table use system heap when
  378.                                     appropriate.
  379.         <99>      2/2/94    CC        Revised PrepareLinksForClone() and
  380.                                     AnnotateLinksForNextClone().
  381.         <98>      2/2/94    RR        Added isRoot to CreateFrame
  382.         <97>      2/1/94    CC        Added PrepareLinksForClone()
  383.                                     AnnotateLinksForNextClone(), and non-member
  384.                                     support functions; not yet called by
  385.                                     EndClone().  Added XMPCloneType argument to
  386.                                     BeginClone.
  387.         <96>     1/28/94    CC        Removed UniqueUpdateID(),
  388.                                     ShowLinkBorders(), and SetLinkBorders().
  389.                                     Implemented Purge() (VL).  Abort() now
  390.                                     releases draft properties (VL).  Fixed
  391.                                     sequence of deletions in
  392.                                     RemovePersistentObject() (VL).
  393.                                     DeleteCollections() - call ReleaseAll() on
  394.                                     all objects, then delete all objects.
  395.         <95>     1/27/94    VL        Used ReleaseAll. Fixed up
  396.                                     ReleasePersistentObject. Added
  397.                                     IsValidDraftKey.
  398.         <94>     1/25/94    CC        Use fShowLinkBorders field.
  399.         <93>     1/22/94    CC        AcquireLink(), AcquireLinkSource(): Avoid infinite
  400.                                     recursion by adding persistent object to
  401.                                     the draft before calling
  402.                                     InitFromStorageUnit().
  403.         <92>     1/21/94    CC        Added CreateLinkSource(), AcquireLinkSource(),
  404.                                     RemoveLinkSource(), and
  405.                                     AcquireLinkSourceIterator().  Moved calls to
  406.                                     XMPLinkManager::DraftOpened,
  407.                                     ::DraftClosing, and ::DraftSaved into
  408.                                     document shell.
  409.         <91>     1/21/94    CG        Renamed kXMPEmbeddedContainer to
  410.                                     kXMPBentoEmbeddedContainer.  Changed calls
  411.                                     to NewObject to take current heap.
  412.         <90>     1/18/94    CG        Added include for BentoDef.h for
  413.                                     kXMPEmbeddedContainer.
  414.         <89>     1/18/94    CC        Added stub implementations of
  415.                                     ShowLinkBorders() and SetLinkBorders();
  416.                                     changed DraftClosed() to DraftClosing().
  417.         <88>     1/15/94    VL        Made sure that the Part Destructor is
  418.                                     called.
  419.         <87>     1/14/94    CC        Externalize(): Call
  420.                                     XMPLinkManager::DraftSaved();
  421.                                     RemoveChanges(): Call
  422.                                     XMPLinkManager::DraftClosed().
  423.         <86>     1/12/94    CG        Changed CreatePart and AcquirePart to use the
  424.                                     new Binding object in ASLM build.
  425.         <85>     1/12/94    VL        Init... Changes.
  426.         <84>    12/22/93    CC        AcquireLink() - Better error handling and
  427.                                     clean-up.
  428.         <83>    12/21/93    VL        Added support for Persistent Link ID.
  429.         <82>    12/21/93    JBS        CreateFrame with viewType & presentation
  430.         <81>    12/20/93    SS        Added PartsBin to Get/CreatePart
  431.         <80>    12/20/93    VL        Removed window-related stuff (XMPWindow is
  432.                                     no longer a persistent object).
  433.         <79>    12/16/93    CC        AcquireLink: Instantiate link objects, moved
  434.                                     code into LinkMgr.cp.  CreateLink: object
  435.                                     type is kXMPLink not kXMPPart!
  436.         <78>    12/16/93    TÇ        CreatePart now takes an optional Editor
  437.                                     parameter
  438.         <77>    12/14/93    VL        Added private methods to GetCMContainer and
  439.                                     used AcquireDraft instead of fDraft.
  440.         <76>    12/14/93    TÇ        InitFrame, InitLink, InitWindow changes.
  441.                                     PstObj::Initialize, PstObj:Internalize,
  442.                                     PstObj::InitializePersistent all went away.
  443.         <75>    12/13/93    TÇ        InitPart changes
  444.         <74>     12/8/93    CC        Changes to CreateLinkSpec
  445.                                     AcquireLink sends apple event to resolve
  446.                                     linkSpec.
  447.         <73>     12/3/93    TÇ        Stop including XMPError.h, it is included
  448.                                     as ErrorDef.h inside Except.h
  449.         <72>    11/30/93    VL        Changed frameGroup from XMPUShort to
  450.                                     XMPULong.
  451.         <71>    11/24/93    VL        Added document check in Initialize.
  452.         <70>    11/23/93    VL        Made XMPDraft pool-aware.
  453.         <69>    11/18/93    PH        Call parent method in
  454.                                     RemovePersistentObject
  455.         <68>    11/18/93    PH        Fixed RemovePersistentObject to call
  456.                                     Release before calling delete
  457.         <67>    11/17/93    CC        Fixed CreateLink to compile with CFront.
  458.         <66>    11/16/93    EL        Use OpenDoc instead of Amber.
  459.         <65>    11/16/93    SS        Reactivated DragPart
  460.         <64>    11/16/93    EL        Part name is ISOStr and should be null
  461.                                     terminated.
  462.         <63>    11/15/93    CC        Implemented AcquireLink for LinkSpec parameter
  463.                                     Implemented CreateLink and CreateLinkSpec
  464.                                     Added IsMyProcess
  465.         <62>    11/12/93    JBS        remove Layout methods
  466.         <61>     11/9/93    PH        Added CreateDragDropStorageUnit
  467.         <60>     11/4/93    SS        Added #ifdef QUALITY_PARTS too
  468.                                     Get/CreatePart for quality team
  469.         <59>     11/1/93    VL        Added BeginClone, EndClone and AbortClone.
  470.                                     Collapsed fStorageUnits and
  471.                                     fReleasedStorageUnits into one hash table.
  472.                                     Collapsed fPersistentObjects and
  473.                                     fReleasedPersistentObjects into one hash
  474.                                     table.
  475.         <58>    10/29/93    PH        Fix AcquirePart and add check to
  476.                                     ReleaseStorageU
  477.         <57>    10/21/93    RR        CreateWindow takes new window flags (at
  478.                                     least until we have new Initialize strategy
  479.                                     for SOM)
  480.         <56>    10/12/93    VL        Uncommented WASSERTs. Release
  481.                                     fDraftProperties in ::RemoveChanges.
  482.         <55>     10/8/93    VL        Temporarily removed WASSERT.
  483.         <54>     10/7/93    RR        Added rootPart to CreateWindow call
  484.         <53>     10/7/93    VL        Moved error codes to XMPError.h.
  485.         <52>     10/6/93    TÇ        remove obsolete parts (StylPart)
  486.         <51>     9/30/93    VL        Removed SetFinished.
  487.         <50>     9/30/93    VL        Removed unnecessary STORAGE_TEST ifdefs.
  488.         <49>     9/29/93    VL        Added code for smart internalization.
  489.         <48>     9/24/93    PH        Use new AppleTEXT
  490.         <47>     9/24/93    VL        Removed unnecessary Throws.
  491.         <46>     9/24/93    JA        Minor syntactic tweaks for THINK C++.
  492.         <45>     9/23/93    VL        Added code to handle StorageUnitType
  493.                                     property. Fixed SetName to use Exists
  494.                                     instead of exception. Moved methods around
  495.                                     to conform to .h file.
  496.         <44>     9/22/93    JA        Updated ASSERTs for new macro.
  497.         <43>     9/21/93    VL        Avoid creating unnecessary versions.
  498.         <42>     9/16/93    JA        Fixed polarity of ASSERTs.
  499.         <40>     9/14/93    VL        Made Draft thread-safe.
  500.         <39>      9/9/93    VL        Set up the Session global for
  501.                                     EmbeddedContainers. Fixed casting problem
  502.                                     caused in <38>.
  503.         <38>      9/9/93    VL        Fixed RemovePersistentObject to
  504.                                     CMDeleteObject the real object, not ID.
  505.         <37>      9/8/93    VL        Draft can handle flushing now.
  506.         <36>      9/7/93    PH        Add code to create a DragPart
  507.         <35>      9/3/93    JBS        added support for XMPLayout class
  508.         <34>     8/26/93    VL        Used new VersionList calls.
  509.         <33>     8/23/93    VL        Added FailIfNotExclusiveWrite check. Used
  510.                                     fExternalized flag to show the state of the
  511.                                     draft. Implemented NeedExternalizing.
  512.         <32>     8/20/93    TÇ        Commented out #ifdef PROTOTYPEBUILD stuff
  513.                                     so that the implementation shell could use
  514.                                     the full functionality of Draft
  515.         <31>     8/20/93    VL        Cast XMPPtr to XMPName.
  516.         <30>     8/20/93    VL        Used ODMemory.h
  517.         <29>     8/19/93    VL        Put in CMDeleteObject again.
  518.         <28>     8/18/93    VL        ReleaseStorageUnit takes an ID now.
  519.         <27>     8/18/93    PH        Don't call CMDeleteObject in
  520.                                     RemoveStorageUnit
  521.         <26>     8/18/93    VL        Fixed ReleaseSTorageUnit.
  522.         <25>     8/17/93    PH        Call internalize in AcquirePart and don't
  523.                                     increment the ref count of the SU in
  524.                                     GetPstObj if the object exists
  525.         <24>     8/13/93    VL        Used VersionList::GetLatestVersionID.
  526.                                     Commented out some code in Externalize.
  527.         <23>     8/12/93    VL        Made GetName raise an exception instead of
  528.                                     returning kXMPNULL. Used kXMP props and
  529.                                     types.
  530.         <22>     8/11/93    VL        ifdef out implementation code for
  531.                                     CreateFrame because the XMPFrame class is
  532.                                     not there yet.
  533.         <21>     8/10/93    VL        Put some real code in CreateFrame.
  534.         <20>     8/10/93    PH        Call release on su in ReleasePstObj
  535.         <19>     8/10/93    PH        Really fix ReleasePstObj
  536.         <18>      8/9/93    PH        Fix ReleasePersistentObject to do ref
  537.                                     counting properly
  538.         <17>      8/9/93    VL        Moved error code to XMPError.h.
  539.         <16>      8/6/93    PH        Change kPartType to kXMPPart
  540.         <15>      8/6/93    VL        Used CreateCollections and
  541.                                     DeleteCollections.
  542.         <14>      8/6/93    PH        Storage integration
  543.         <13>      8/6/93    VL        Added support for
  544.                                     creating/getting/releasing/removing
  545.                                     persistent objects.
  546.         <12>     7/29/93    VL        Removed getting persistent objects by name.
  547.                                     Implemented GetName and SetName.
  548.         <11>     7/23/93    VL        Removed root SU creation code in
  549.                                     AcquireDraftPropertiesObject.
  550.         <10>     7/14/93    VL        Implemented basic storage unit functions.
  551.          <9>      7/6/93    VL        Implemented RemoveFromDocument.
  552.          <8>      7/6/93    VL        XMPStorageUnitName should be
  553.                                     XMPStorageUnitName* in AcquireStorageUnit.
  554.          <7>      7/2/93    TÇ        CreateSU should take XMPType, not XMPName.
  555.          <6>     6/30/93    VL        Changed XMPName to XMPType.
  556.          <5>     6/30/93    VL        Added Reinitialize, Open, Close, Abort.
  557.                                     Also added utility calls
  558.                                     Open/Close/AbortVersion.
  559.          <4>     6/22/93    VL        Used RefCount from RefCtObj. Added
  560.                                     SetChangedFromPrev() and
  561.                                     AcquireDraftPropertiesObject. Initialize() gets
  562.                                     SU for Draft Properties.
  563.          <3>     6/15/93    VL        Put it some test code.
  564.          <1>      6/2/93    VL        first checked in
  565.  
  566.     To Do:
  567.     In Progress:
  568.         
  569. */
  570.  
  571. #define CMDraft_Class_Source
  572. #define VARIABLE_MACROS
  573. #include <CMDraft.xih>
  574.  
  575. #ifndef _DRAFPRIV_
  576. #include "DrafPriv.h"
  577. #endif
  578.  
  579. #ifndef SOM_ODSession_xh
  580. #include <ODSessn.xh>
  581. #endif
  582.  
  583. #ifndef SOM_CMDocument_xh
  584. #include <CMDoc.xh>
  585. #endif
  586.  
  587. #ifndef SOM_CMStorageUnit_xh
  588. #include <CMSU.xh>
  589. #endif
  590.  
  591. #ifndef _DOCPRIV_
  592. #include "DocPriv.h"
  593. #endif
  594.  
  595. #ifndef SOM_ODContainer_xh
  596. #include <ODCtr.xh>
  597. #endif
  598.  
  599. #ifndef SOM_ODStorageSystem_xh
  600. #include <ODStor.xh>
  601. #endif
  602.  
  603. #ifndef SOM_ODStorageUnitCursor_xh
  604. #include <SUCursor.xh>
  605. #endif
  606.  
  607. #ifndef SOM_ODFrame_xh
  608. #include <Frame.xh>
  609. #endif
  610.  
  611. #ifndef SOM_ODLink_xh
  612. #include <Link.xh>
  613. #endif
  614.  
  615. #ifndef SOM_ODLinkSource_xh
  616. #include <LinkSrc.xh>
  617. #endif
  618.  
  619. #ifndef SOM_ODLinkSpec_xh
  620. #include <LinkSpec.xh>
  621. #endif
  622.  
  623. #ifndef SOM_ODLinkManager_xh
  624. #include <LinkMgr.xh>
  625. #endif
  626.  
  627. #ifndef SOM_ODPart_xh
  628. #include <Part.xh>
  629. #endif
  630.  
  631. #ifndef _EXCEPT_
  632. #include "Except.h"
  633. #endif
  634.  
  635. #ifndef SOM_ODBentoContainer_xh
  636. #include "CMCtr.xh"
  637. #endif
  638.  
  639. #ifndef _CMAPI_
  640. #include "CMAPI.h"
  641. #endif
  642.  
  643. #ifndef __CM_API_TYPE_
  644. #include "CMAPITYP.h"
  645. #endif
  646.  
  647. #ifndef SOM_ODEmbeddedContainer_xh
  648. #include <EmbedCtr.xh>
  649. #endif
  650.  
  651. #ifndef _SESSHDR_
  652. #include "SessHdr.h"
  653. #endif
  654.  
  655. #ifndef _ODMEMORY_
  656. #include "ODMemory.h"
  657. #endif
  658.  
  659. #ifndef _ODNEW_
  660. #include "ODNew.h"
  661. #endif
  662.  
  663. #ifndef SOM_Module_OpenDoc_StdProps_defined
  664. #include <StdProps.xh>
  665. #endif
  666.  
  667. #ifndef SOM_Module_OpenDoc_StdTypes_defined
  668. #include <StdTypes.xh>
  669. #endif
  670.  
  671. #ifndef SOM_CMLinkIterator_xh
  672. #include <CMLkItr.xh>
  673. #endif
  674.  
  675. #ifndef SOM_CMLinkSourceIterator_xh
  676. #include <CMLkSItr.xh>
  677. #endif
  678.  
  679. #ifndef _INDHDR_
  680. #include "IndHdr.h"            // for some const ODName
  681. #endif
  682.  
  683. #ifndef _OPENHASH_
  684. #include "OpenHash.h"
  685. #endif
  686.  
  687. #ifndef _ISOSTR_
  688. #include "ISOStr.h"
  689. #endif
  690.  
  691. #ifndef __STRING__
  692. #include <string.h>            // For strlen, strcpy....
  693. #endif
  694.  
  695. #ifndef _ODDEBUG_
  696. #include "ODDebug.h"    // Adkins -- added
  697. #endif
  698.  
  699. #ifndef _STORUTIL_
  700. #include <StorUtil.h>
  701. #endif
  702.  
  703. #ifndef SOM_ODBinding_xh
  704. #include <ODBindng.xh>
  705. #endif
  706.  
  707. #ifndef SOM_ODPartWrapper_xh
  708. #include <PartWrap.xh>
  709. #endif
  710.  
  711. #ifndef _BENTODEF_
  712. #include "BentoDef.h"
  713. #endif
  714.  
  715. #ifndef _BARRAY_
  716. #include <BArray.h>
  717. #endif
  718.  
  719. #ifndef _UTILERRS_
  720. #include "UtilErrs.h"
  721. #endif
  722.  
  723. #ifndef SOM_ODDragAndDrop_xh
  724. #include <DragDrp.xh>
  725. #endif
  726.  
  727. #ifndef SOM_ODArbitrator_xh
  728. #include <Arbitrat.xh>
  729. #endif
  730.  
  731. #ifndef SOM_Module_OpenDoc_Foci_defined
  732. #include <Foci.xh>
  733. #endif
  734.  
  735. #ifndef _ODNEWOBJ_
  736. #include <ODNewObj.h>
  737. #endif
  738.  
  739. #ifndef _STDTYPIO_
  740. #include <StdTypIO.h>
  741. #endif
  742.  
  743. #ifndef _TEMPOBJ_
  744. #include <TempObj.h>
  745. #endif
  746.  
  747. #ifndef SOM_Module_OpenDoc_StdDefs_defined
  748. #include <StdDefs.xh>
  749. #endif
  750.  
  751. #ifndef SOM_SOMClassMgr_xh
  752. #include <somcm.xh>
  753. #endif
  754.  
  755. #pragma segment CMDraft
  756.  
  757. //==============================================================================
  758. // Constants
  759. //==============================================================================
  760.  
  761. const ODType    kODVersionNamePrefix = "+//ISO 9070/ANSI::113722::US::CI LABS::OpenDoc:Property:Bento Version Name";
  762. const ODPropertyName kODPropRootSU  = "+//ISO 9070/ANSI::113722::US::CI LABS::OpenDoc:Property:DraftRootStorageUnit";
  763. const ODType    kODStorageUnitType      = "+//ISO 9070/ANSI::113722::US::CI LABS::OpenDoc:Type:StorageUnit";
  764. const ODType    kODStorageUnit            = "+//ISO 9070/ANSI::113722::US::CI LABS::OpenDoc:ObjectType:StorageUnit";
  765. const ODULong    kODInitialNumEntries = 8;
  766.  
  767. const corbastring kFrameClassName = "ODFrame";
  768.  
  769. #define    kMaxStringSize    32
  770. #define kInitialHashTableEntries 8
  771.  
  772. #define lazyOpen 1
  773.  
  774. // For debugging
  775.  
  776. #if ODDebug
  777. // #define ODDebug_Drafts    1
  778. // #define ODDebug_DebugRefCount 1
  779. // #define ODDebug_CMDraft 1
  780. // #define DebugClone 1
  781. // #define ODDebug_VersionList    1
  782. // #define ODDebug_CloningAnnotations 1
  783. // #define ODDebug_Unloading_Classes 1
  784. #endif
  785.  
  786.  
  787. //==============================================================================
  788. // Local Classes
  789. //==============================================================================
  790.  
  791. class SULink : public Link {
  792.  
  793. public:
  794.     
  795.     SULink(ODStorageUnitID fromID, ODStorageUnitID toID)
  796.     {
  797.         fFromID = fromID;
  798.         fToID = toID;
  799.     }
  800.     ~  SULink() {;};
  801.     
  802.     ODStorageUnitID    GetFromID() {return fFromID;};
  803.     ODStorageUnitID    GetToID() {return fToID;};
  804.  
  805. private:
  806.     
  807.     ODStorageUnitID                fFromID;
  808.     ODStorageUnitID                fToID;
  809. };
  810.  
  811. //==============================================================================
  812. // Function Prototypes
  813. //==============================================================================
  814.  
  815. static CMStorageUnit* NewCMStorageUnit(ODMemoryHeapID heapID);
  816.  
  817. static CMObject AcquireDraftPropertiesObject(CMContainer container);
  818. static ODType GetVersionNameFromVersionID(ODVersionID id, ODMemoryHeapID heapID);
  819.  
  820. static void SetOriginalDraft(Environment* ev, ODDraft* targetDraft, ODDraft* originalDraft);
  821. static ODDraft* GetOriginalDraft(Environment* ev, ODDraft* draft);
  822. static ODBoolean OriginalCloneKindExists(Environment* ev, ODDraft* draft);
  823. static void SetOriginalCloneKind(Environment* ev, ODDraft* targetDraft, ODCloneKind cloneKind);
  824.  
  825. static ODBoolean IsLinkObject(Environment* ev, ODDraft* draft, ODID objectID);
  826. static ODBoolean IsLinkSourceObject(Environment* ev, ODDraft* draft, ODID objectID);
  827. static ODBoolean IsEitherLinkObject(Environment* ev, ODDraft* draft, ODID objectID);
  828. static ODBoolean IsNeitherLinkObject(Environment* ev, ODDraft* draft, ODID objectID);
  829.  
  830. static void itoa(ODULong number, ODSByte* cstring);
  831.  
  832. static ODULong PurgeAllStorageUnits(Environment* ev, OpenHashTable* storageUnits, IDList* idList);
  833.  
  834. static void SetupForUpdatingDraft(Environment* ev,
  835.                                         CMDocument* localDoc,
  836.                                         ODVersionID prevVersionID,
  837.                                         CMValue version);            
  838.  
  839. static ODBoolean CheckPartAction(void* k, void* v, ODULong s, void* r);
  840.  
  841. static void CopyProperty(Environment *ev, ODStorageUnit* fromSU, ODStorageUnit* toSU, ODPropertyName prop);
  842. static void CopyDraftAnnotations(Environment *ev, ODStorageUnit* fromSU, ODStorageUnit* toSU);
  843. static void SetStorageUnitType(Environment* ev, ODDraftPermissions perms, ODStorageUnit* su, ODType suType);
  844. static ODISOStr GetStorageUnitType(Environment* ev, ODDraft* draft, ODID objectID);
  845. static ODID RootPartID(Environment* ev, ODDraft* draft);
  846.  
  847. // For debugging
  848.  
  849. #ifdef DebugStorage
  850.  
  851. #define MyDebugStr(s) do {somPrintf(s);} while (0)
  852. #define MyDebug2Str(f,p1,p2) do {somPrintf(f, p1, p2);} while (0)
  853.  
  854. #else
  855.  
  856. #define MyDebugStr(s)
  857. #define MyDebug2Str(f,p1,p2)
  858.  
  859. #endif
  860.  
  861. //==============================================================================
  862. // Static variables
  863. //==============================================================================
  864.  
  865. // Used by CheckPartAction
  866. static CMDraft*    sInterchangeDraft = kODNULL;
  867. static ODISOStr    sSUTypeBuffer;
  868. static ODID        sRootPartIDToIgnore;
  869.  
  870. //------------------------------------------------------------------------------
  871. // ReadClonedObjectTable
  872. //------------------------------------------------------------------------------
  873.  
  874. // These are private property and value for Bento Container Suite. 
  875. // They are used for data interchange. They enable multiple clones to the clipboard
  876. // and d&d container.
  877. const ODPropertyName    kODPropClonedObjectTable  = "OpenDoc:Property:Draft:ClonedObjectTable";
  878. const ODValueType        kODTypeClonedObjectTable  = "OpenDoc:Type:Draft:ClonedObjectTable";
  879.  
  880. ODStatic void ReadClonedObjectTable(Environment* ev, OpenHashTable* clonedSUIDs, ODDraft* destDraft)
  881. {
  882. #ifdef DebugClone
  883.     somPrintf("CMDraft: ReadClonedObjectTable\n");
  884. #endif
  885.  
  886.     TempODStorageUnit su = destDraft->AcquireDraftProperties(ev);
  887.     if (ODSUExistsThenFocus(ev, su, kODPropClonedObjectTable, kODTypeClonedObjectTable) )
  888.     {
  889.         su->SetOffset(ev, 0);
  890.         
  891.         ODULong    size = su->GetSize(ev);
  892.         ODID    fromID;
  893.         ODID    toID;
  894.     
  895.         while ( su->GetOffset(ev) < size )
  896.         {
  897.             StorageUnitGetValue(su, ev, sizeof(ODULong), (ODValue) &fromID);
  898.             StorageUnitGetValue(su, ev, sizeof(ODULong), (ODValue) &toID);
  899. #ifdef DebugClone
  900.             somPrintf("    fromID %d, toID %d\n", fromID, toID);
  901. #endif
  902.             clonedSUIDs->ReplaceEntry(&fromID, &toID);
  903.         }
  904.     }
  905. }
  906.  
  907. //------------------------------------------------------------------------------
  908. // WriteClonedObjectTable
  909. //------------------------------------------------------------------------------
  910.  
  911. ODStatic void WriteClonedObjectTable(Environment* ev, OpenHashTable* clonedSUIDs, ODDraft* destDraft)
  912. {
  913. #ifdef DebugClone
  914.     somPrintf("CMDraft: WriteClonedObjectTable\n");
  915. #endif
  916.  
  917.     TempODStorageUnit su = destDraft->AcquireDraftProperties(ev);
  918.         
  919.     ODSUForceFocus(ev, su, kODPropClonedObjectTable, kODTypeClonedObjectTable);
  920.     
  921.     su->SetOffset(ev, 0);
  922.  
  923.     ODULong    oldSize = su->GetSize(ev);
  924.  
  925.     ODID        fromID;
  926.     ODID        toID;
  927.  
  928.     OpenHashTableIterator iter(clonedSUIDs);
  929.     for (iter.First(&fromID, &toID); iter.IsNotComplete(); iter.Next(&fromID, &toID))
  930.     {
  931. #ifdef DebugClone
  932.         somPrintf("    from ID %d to ID %d\n", fromID, toID);
  933. #endif
  934.         StorageUnitSetValue(su, ev, sizeof(ODULong), (ODValue) &fromID);
  935.         StorageUnitSetValue(su, ev, sizeof(ODULong), (ODValue) &toID);
  936.     }
  937.  
  938.     ODULong    newSize = su->GetOffset(ev);
  939.     if ( oldSize > newSize )
  940.         su->DeleteValue(ev, oldSize - newSize);
  941. }
  942.  
  943. //==============================================================================
  944. // CMDraft
  945. //==============================================================================
  946.  
  947. //------------------------------------------------------------------------------
  948. // CMDraft: FailIfNotExclusiveWrite
  949. //------------------------------------------------------------------------------
  950.  
  951. SOM_Scope void  SOMLINK CMDraftFailIfNotExclusiveWrite(CMDraft *somSelf, Environment *ev)
  952. {
  953.     CMDraftData *somThis = CMDraftGetData(somSelf);
  954.     CMDraftMethodDebug("CMDraft","FailIfNotExclusiveWrite");
  955.  
  956.     if (_fPermissions != kODDPExclusiveWrite)
  957.          ODSetSOMException(ev,kODErrInvalidPermissions);
  958. }
  959.  
  960. //------------------------------------------------------------------------------
  961. // CMDraft: GetDocument
  962. //------------------------------------------------------------------------------
  963.  
  964. SOM_Scope ODDocument*  SOMLINK CMDraftGetDocument(CMDraft *somSelf, Environment *ev)
  965. {
  966.     CMDraftData *somThis = CMDraftGetData(somSelf);
  967.     CMDraftMethodDebug("CMDraft","GetDocument");
  968.  
  969.     return _fDocument;
  970. }
  971.  
  972. //------------------------------------------------------------------------------
  973. // CMDraft: GetID
  974. //------------------------------------------------------------------------------
  975.  
  976. SOM_Scope ODDraftID  SOMLINK CMDraftGetID(CMDraft *somSelf, Environment *ev)
  977. {
  978.     CMDraftData *somThis = CMDraftGetData(somSelf);
  979.     CMDraftMethodDebug("CMDraft","GetID");
  980.  
  981.     return _fID;
  982. }
  983.  
  984. //------------------------------------------------------------------------------
  985. // CMDraft: AcquireDraftProperties
  986. //------------------------------------------------------------------------------
  987.  
  988. SOM_Scope ODStorageUnit*  SOMLINK CMDraftAcquireDraftProperties(CMDraft *somSelf, Environment *ev)
  989. {
  990.     CMDraftData *somThis = CMDraftGetData(somSelf);
  991.     CMDraftMethodDebug("CMDraft","AcquireDraftProperties");
  992.  
  993.     SOM_CATCH return kODNULL;
  994.     
  995.     CMObject            draftPropertiesObject;
  996.     CMStorageUnit*        draftProperties;
  997.     ODStorageUnitID    id;
  998.     
  999.     if (_fDraftProperties != kODNULL) {
  1000.         _fDraftProperties->Internalize(ev);
  1001.     }
  1002.     else {
  1003.  
  1004.         CMContainer cmContainer = somSelf->GetCMContainer(ev);
  1005.         ODSessionMustHaveCMAllocReserve(cmContainer);
  1006.         // AcquireDraftPropertiesObject() makes CM calls:
  1007.  
  1008.         draftPropertiesObject = AcquireDraftPropertiesObject(somSelf->GetCMContainer(ev));
  1009.         if (draftPropertiesObject == kODNULL)
  1010.             THROW(kODErrNoDraftProperties);
  1011.         
  1012.         id = _fIDList->Add(draftPropertiesObject);
  1013.         draftProperties = NewCMStorageUnit(somSelf->GetHeap(ev));
  1014.         draftProperties->InitStorageUnit(ev, somSelf, id);
  1015.         _fStorageUnits->ReplaceEntry(&id, &draftProperties);
  1016.         _fDraftProperties = draftProperties;
  1017.         
  1018.         ODSessionRestoreCMAllocReserve(cmContainer);
  1019.     }
  1020.     
  1021.     _fDraftProperties->Acquire(ev);
  1022.     return _fDraftProperties;
  1023. }
  1024.  
  1025. //------------------------------------------------------------------------------
  1026. // CMDraft: Acquire
  1027. //------------------------------------------------------------------------------
  1028.  
  1029. SOM_Scope void  SOMLINK CMDraftAcquire(CMDraft *somSelf, Environment *ev)
  1030. {
  1031. //  CMDraftData *somThis = CMDraftGetData(somSelf);
  1032.     CMDraftMethodDebug("CMDraft","Acquire");
  1033.  
  1034.     SOM_TRY
  1035.         parent_Acquire(somSelf, ev);
  1036.     SOM_CATCH_ALL
  1037.     SOM_ENDTRY
  1038. }
  1039.  
  1040. //------------------------------------------------------------------------------
  1041. // CMDraft: Release
  1042. //------------------------------------------------------------------------------
  1043.  
  1044. SOM_Scope void  SOMLINK CMDraftRelease(CMDraft *somSelf, Environment *ev)
  1045. {
  1046.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1047.     CMDraftMethodDebug("CMDraft","Release");
  1048.  
  1049.     SOM_TRY
  1050.     
  1051.     parent_Release(somSelf, ev);
  1052.     if (somSelf->GetRefCount(ev) == 0) {
  1053.         if (_fDraftProperties != kODNULL) {
  1054.             _fDraftProperties->Release(ev);
  1055.             _fDraftProperties = kODNULL;
  1056.         }
  1057. //        WASSERTM((somSelf->AreEmptyCollections(ev) != kODFalse), "OutstandingObjects in CMDraft: Release.");
  1058.         _fDocument->ReleaseDraft(ev, somSelf);
  1059.     }
  1060.     
  1061.     SOM_CATCH_ALL
  1062.     
  1063.         ODError err = ErrorCode();
  1064.  
  1065.         WARN("Error occurred in ODContainer::Release: %d %s", err, ErrorMessage() ?ErrorMessage() :"");
  1066.  
  1067.         if (err == kODErrBentoErr)
  1068.             SetErrorCode(kODErrFatalContainerError);
  1069.         else if (err != kODErrFatalContainerError)
  1070.             SetErrorCode(kODNoError);
  1071.  
  1072.     SOM_ENDTRY
  1073. }
  1074.  
  1075. //------------------------------------------------------------------------------
  1076. // CMDraft: GetPermissions
  1077. //------------------------------------------------------------------------------
  1078.  
  1079. SOM_Scope ODDraftPermissions  SOMLINK CMDraftGetPermissions(CMDraft *somSelf, Environment *ev)
  1080. {
  1081.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1082.     CMDraftMethodDebug("CMDraft","GetPermissions");
  1083.  
  1084.     return _fPermissions;
  1085. }
  1086.  
  1087. //------------------------------------------------------------------------------
  1088. // CMDraft: CreateStorageUnit
  1089. //------------------------------------------------------------------------------
  1090.  
  1091. SOM_Scope ODStorageUnit*  SOMLINK CMDraftCreateStorageUnit(CMDraft *somSelf, Environment *ev)
  1092. {
  1093.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1094.     CMDraftMethodDebug("CMDraft","CreateStorageUnit");
  1095.  
  1096.     ODStorageUnit*    su = kODNULL; ODVolatile(su);
  1097.  
  1098.     SOM_TRY
  1099.  
  1100.     somSelf->FailIfNotExclusiveWrite(ev);
  1101.     
  1102.     su = somSelf->CreateSU(ev, kODNULL, kODStorageUnit);
  1103.     SetStorageUnitType(ev, _fPermissions, su, kODStorageUnit);
  1104.  
  1105.     somSelf->SetChangedFromPrevFlag(ev, kODTrue);
  1106.  
  1107.     SOM_CATCH_ALL
  1108.         if (su != kODNULL) {
  1109.             TRY{
  1110.                 somSelf->ReleaseStorageUnit(ev, su->GetID(ev));
  1111.             }CATCH_ALL{
  1112.                 // ignore exception
  1113.             }ENDTRY
  1114.             su = kODNULL;
  1115.         }
  1116.     SOM_ENDTRY
  1117.     return su;
  1118. }
  1119.  
  1120. //------------------------------------------------------------------------------
  1121. // CMDraft: IsValidID
  1122. //------------------------------------------------------------------------------
  1123.  
  1124. SOM_Scope ODBoolean  SOMLINK CMDraftIsValidID(CMDraft *somSelf, Environment *ev,
  1125.         ODID id)
  1126. {
  1127.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1128.     CMDraftMethodDebug("CMDraft","IsValidID");
  1129.  
  1130.     SOM_TRY
  1131.     
  1132.     if ( id != kODNULLID )
  1133.         return _fIDList->Exists(id);
  1134.     
  1135.     SOM_CATCH_ALL
  1136.     SOM_ENDTRY
  1137.     return kODFalse;
  1138. }
  1139.  
  1140. //------------------------------------------------------------------------------
  1141. // CMDraft: AcquireStorageUnit
  1142. //------------------------------------------------------------------------------
  1143.  
  1144. SOM_Scope ODStorageUnit*  SOMLINK CMDraftAcquireStorageUnit(CMDraft *somSelf, Environment *ev,
  1145.         ODStorageUnitID id)
  1146. {
  1147.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1148.     CMDraftMethodDebug("CMDraft","AcquireStorageUnit");
  1149.  
  1150.     SOM_CATCH return kODNULL;
  1151.  
  1152.     if (id == kODNULLID)
  1153.         THROW(kODErrIllegalNullIDInput);
  1154.  
  1155.     ODStorageUnit*    su = kODNULL;
  1156.     
  1157.     if (_fStorageUnits->GetValue(&id, &su)) {
  1158.         su->Acquire(ev);
  1159.     }
  1160.     else if ((_fIDList->Exists(id) == kODFalse) ||
  1161.              (_fIDList->Get(id) != kODNULL)) {
  1162.         su = somSelf->CreateSU(ev, id, kODStorageUnit);
  1163.     }
  1164.     return su;
  1165. }
  1166.  
  1167. //------------------------------------------------------------------------------
  1168. // CMDraft: RemoveStorageUnit
  1169. //------------------------------------------------------------------------------
  1170.  
  1171. SOM_Scope void  SOMLINK CMDraftRemoveStorageUnit(CMDraft *somSelf, Environment *ev,
  1172.         ODStorageUnit* su)
  1173. {
  1174.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1175.     CMDraftMethodDebug("CMDraft","RemoveStorageUnit");
  1176.  
  1177.     SOM_CATCH return;
  1178.  
  1179.     CMContainer cmContainer = somSelf->GetCMContainer(ev);
  1180.     ODSessionMustHaveCMAllocReserve(cmContainer);
  1181.     
  1182.     ODID            id;
  1183.     CMObject        object;
  1184.     ODStorageUnit*    draftProperties;
  1185.  
  1186.     somSelf->FailIfNotExclusiveWrite(ev);
  1187.     
  1188.     draftProperties = somSelf->AcquireDraftProperties(ev);
  1189.     if (su == draftProperties) {
  1190.         draftProperties->Release(ev);
  1191.         THROW(kODErrIllegalOperationOnSU);
  1192.     }
  1193.     else
  1194.         draftProperties->Release(ev);
  1195.         
  1196.     // Get Storage Unit ID
  1197.     
  1198.     id = su->GetID(ev);
  1199.     if (id == kODNULL)
  1200.         THROW(kODErrInvalidStorageUnit);
  1201.         
  1202.     // Release the storage unit
  1203.     su->Release(ev);
  1204.     
  1205.     // Remove Storage Unit from outstanding SU collection
  1206.     
  1207.     _fStorageUnits->RemoveEntry(&id);
  1208.     
  1209.     // Get and delete the CMObject associated with su.
  1210.     
  1211.     object = (CMObject) _fIDList->Get(id);
  1212.     
  1213.     // Remove the entry in the ID-object collection.
  1214.     
  1215.     _fIDList->Remove(id);
  1216.     
  1217.     // Delete the object
  1218.     
  1219.     if (object != kODNULL)
  1220.         CMDeleteObject(object);
  1221.     
  1222.     // Destroy su
  1223.     
  1224.     delete su;
  1225.     
  1226.     // Mark this draft dirty
  1227.     
  1228.     somSelf->SetChangedFromPrevFlag(ev, kODTrue);
  1229.  
  1230.     ODSessionRestoreCMAllocReserve(cmContainer);
  1231. }
  1232.  
  1233. //------------------------------------------------------------------------------
  1234. // CMDraft: ChangedFromPrev
  1235. //------------------------------------------------------------------------------
  1236.  
  1237. SOM_Scope ODBoolean  SOMLINK CMDraftChangedFromPrev(CMDraft *somSelf, Environment *ev)
  1238. {
  1239.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1240.     CMDraftMethodDebug("CMDraft","ChangedFromPrev");
  1241.     
  1242.     SOM_CATCH return kODFalse;
  1243.  
  1244.     ODBoolean        changedFromPrev;
  1245.     VersionList*    versionList = kODNULL;
  1246.     
  1247.     versionList = _fDocument->TestAndGetVersionList(ev);
  1248.     ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  1249.     
  1250.     TRY
  1251.         changedFromPrev = somSelf->IsChangedFromPrev(ev, versionList);
  1252.         
  1253.     CATCH_ALL
  1254.     
  1255.         _fDocument->ReleaseVersionList(ev);
  1256.         RERAISE;
  1257.         
  1258.     ENDTRY
  1259.     
  1260.     _fDocument->ReleaseVersionList(ev);
  1261.     
  1262.     return changedFromPrev;
  1263. }
  1264.  
  1265. //------------------------------------------------------------------------------
  1266. // CMDraft: SetChangedFromPrev
  1267. //------------------------------------------------------------------------------
  1268.  
  1269. SOM_Scope void  SOMLINK CMDraftSetChangedFromPrev(CMDraft *somSelf, Environment *ev)
  1270. {
  1271.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1272.     CMDraftMethodDebug("CMDraft","SetChangedFromPrev");
  1273.  
  1274.     SOM_CATCH return;
  1275.     
  1276.     somSelf->FailIfNotExclusiveWrite(ev);
  1277.  
  1278.     somSelf->SetChangedFromPrevFlag(ev, kODTrue);
  1279. }
  1280.  
  1281. //------------------------------------------------------------------------------
  1282. // CMDraft: RemoveFromDocument
  1283. //------------------------------------------------------------------------------
  1284.  
  1285. SOM_Scope void  SOMLINK CMDraftRemoveFromDocument(CMDraft *somSelf, Environment *ev)
  1286. {
  1287.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1288.     CMDraftMethodDebug("CMDraft","RemoveFromDocument");
  1289.  
  1290.     SOM_CATCH return;
  1291.     
  1292.     _fDocument->CollapseDrafts(ev, somSelf, kODNULL);
  1293. }
  1294.  
  1295. //------------------------------------------------------------------------------
  1296. // CMDraft: RemoveChanges
  1297. //------------------------------------------------------------------------------
  1298.  
  1299. SOM_Scope ODDraft*  SOMLINK CMDraftRemoveChanges(CMDraft *somSelf, Environment *ev)
  1300. {
  1301.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1302.     CMDraftMethodDebug("CMDraft","RemoveChanges");
  1303.     
  1304.     SOM_CATCH return somSelf;
  1305.     
  1306.     VersionList*    versionList = kODNULL;
  1307.     
  1308.     somSelf->FailIfNotExclusiveWrite(ev);
  1309.     
  1310.     if (_fDraftProperties != kODNULL) {
  1311.         _fDraftProperties->Release(ev);
  1312.         _fDraftProperties = kODNULL;
  1313.     }
  1314.     
  1315. //    WASSERTM((somSelf->AreEmptyCollections(ev) != kODFalse), "OutstandingObjects in CMDraft: RemoveChanges.");
  1316.     
  1317.     somSelf->DestroyVersion(ev);
  1318.     
  1319.     versionList = _fDocument->TestAndGetVersionList(ev);
  1320.     ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  1321.  
  1322. #ifdef ODDebug_VersionList
  1323.     _fDocument->GetVersionList(ev)->Print(">>> Entering RemoveChanges");
  1324. #endif
  1325.  
  1326.     TRY
  1327.         if (versionList->Exists(_fID) != kODFalse)
  1328.             versionList->RemoveChanges(_fID);
  1329.         
  1330.     CATCH_ALL
  1331.     
  1332.         _fDocument->ReleaseVersionList(ev);
  1333.         RERAISE;
  1334.  
  1335.     ENDTRY
  1336.  
  1337. #if !TestFlushContainer
  1338.     _fDocument->ExternalizeVersionList(ev, kODFalse);
  1339. #endif
  1340.     _fDocument->ReleaseVersionList(ev);
  1341.         
  1342.     somSelf->Open(ev);
  1343.     
  1344.     somSelf->SetChangedFromPrevFlag(ev, kODFalse);
  1345.  
  1346. #ifdef ODDebug_VersionList
  1347.     _fDocument->GetVersionList(ev)->Print(">>> Exiting RemoveChanges");
  1348. #endif
  1349.  
  1350.     return somSelf;
  1351. }
  1352.  
  1353. //------------------------------------------------------------------------------
  1354. // CMDraft: Externalize
  1355. //------------------------------------------------------------------------------
  1356.  
  1357. SOM_Scope ODDraft*  SOMLINK CMDraftExternalize(CMDraft *somSelf, Environment *ev)
  1358. {
  1359.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1360.     CMDraftMethodDebug("CMDraft","Externalize");
  1361.  
  1362.     SOM_CATCH return somSelf;
  1363.     
  1364.     somSelf->ExternalizeCollections(ev);
  1365.     
  1366.     _fExternalized = kODTrue;
  1367.         
  1368.     // DO THE ACTUAL EXTERNALIZATION HERE
  1369.     
  1370.     somSelf->FlushVersion(ev);
  1371.     
  1372.     return somSelf;
  1373. }
  1374.  
  1375. //------------------------------------------------------------------------------
  1376. // CMDraft: SaveToAPrevious
  1377. //------------------------------------------------------------------------------
  1378.  
  1379. SOM_Scope ODDraft*  SOMLINK CMDraftSaveToAPrevious(CMDraft *somSelf, Environment *ev,
  1380.         ODDraft* to)
  1381. {
  1382.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1383.     CMDraftMethodDebug("CMDraft","SaveToAPrevious");
  1384.  
  1385.     SOM_CATCH return somSelf;
  1386.  
  1387.     _fDocument->SaveToAPrevDraft(ev, somSelf, to);
  1388.     return somSelf;
  1389. }
  1390.  
  1391. //------------------------------------------------------------------------------
  1392. // CMDraft: CreateFrame
  1393. //------------------------------------------------------------------------------
  1394.  
  1395. SOM_Scope ODFrame*  SOMLINK CMDraftCreateFrame(CMDraft *somSelf, Environment *ev,
  1396.         ODObjectType        frameType,
  1397.         ODFrame*    containingFrame,
  1398.         ODShape*     frameShape,
  1399.         ODCanvas*    biasCanvas,
  1400.         ODPart*         part,
  1401.         ODTypeToken    viewType,
  1402.         ODTypeToken    presentation,
  1403.         ODBoolean        isSubframe,
  1404.         ODBoolean         isOverlaid)
  1405. {
  1406.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1407.     CMDraftMethodDebug("CMDraft","CreateFrame");
  1408.  
  1409.     ODStorageUnit*        su = kODNULL;
  1410.     ODFrame*            frame = kODNULL;
  1411.     ODStorageUnitID        id = kODNULLID;
  1412.  
  1413.     ODVolatile(su);
  1414.     ODVolatile(frame);
  1415.     ODVolatile(id);
  1416.  
  1417.     SOM_TRY
  1418.  
  1419.         if (ODISOStrEqual(frameType, kODFrameObject) != kODFalse)    
  1420.             somSelf->FailIfNotExclusiveWrite(ev);
  1421.  
  1422.         frame = new ODFrame();
  1423.         if (frame == kODNULL)
  1424.             THROW(kODErrCannotCreateFrame);
  1425.         
  1426.          if (ODISOStrEqual(frameType, kODFrameObject) != kODFalse) {
  1427.             su = somSelf->CreateSU(ev, kODNULL, kODFrameObject);
  1428.             SetStorageUnitType(ev, _fPermissions, su, kODFrameObject);
  1429.             id = su->GetID(ev);
  1430.             _fPersistentObjects->ReplaceEntry(&id, &frame);
  1431.             frame->InitFrame(ev, su, containingFrame, frameShape, biasCanvas, part,
  1432.                              viewType, presentation, isSubframe, isOverlaid);
  1433.             somSelf->SetChangedFromPrevFlag(ev, kODTrue);
  1434.         }
  1435.         else if (ODISOStrEqual(frameType, kODNonPersistentFrameObject) != kODFalse) {
  1436.             id = _fIDList->Add(kODNULL);
  1437.             _fPersistentObjects->ReplaceEntry(&id, &frame);
  1438.             frame->InitFrameNonPersistent(ev, somSelf, id, containingFrame, frameShape,
  1439.                         biasCanvas, part, viewType, presentation, isSubframe, isOverlaid);
  1440.         }
  1441.         else
  1442.             THROW(kODErrInvalidObjectType);
  1443.  
  1444.     
  1445.     SOM_CATCH_ALL
  1446.         if (frame != kODNULL) {
  1447.             TRY{
  1448.                 if (id != kODNULLID)
  1449.                 {
  1450.                     if (su == kODNULL)
  1451.                     {
  1452.                         // This is just for non-persistent frame.
  1453.                         // Every other real persistent object should use RemovePersistentObject.
  1454.                         ODReleaseObject(ev, frame);
  1455.                         _fPersistentObjects->RemoveEntry(&id);
  1456.                     }
  1457.                     else
  1458.                         somSelf->RemovePersistentObject(ev, frame);
  1459.                 }
  1460.                 else {
  1461.                     delete frame;
  1462.                     if (su != kODNULL)
  1463.                         somSelf->RemoveStorageUnit(ev, su);
  1464.                 }
  1465.             }CATCH_ALL{
  1466.                 // ignore exception
  1467.             }ENDTRY
  1468.             frame = kODNULL;
  1469.         }
  1470.     SOM_ENDTRY
  1471.         
  1472.     return frame;
  1473. }
  1474.  
  1475. //------------------------------------------------------------------------------
  1476. // CMDraft: AcquireFrame
  1477. //------------------------------------------------------------------------------
  1478.  
  1479. SOM_Scope ODFrame*  SOMLINK CMDraftAcquireFrame(CMDraft *somSelf, Environment *ev,
  1480.         ODStorageUnitID id)
  1481. {
  1482.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1483.     CMDraftMethodDebug("CMDraft","AcquireFrame");
  1484.  
  1485.     ODStorageUnit*    su = kODNULL; ODVolatile(su);
  1486.     ODFrame*        frame = kODNULL; ODVolatile(frame);
  1487.  
  1488.     SOM_TRY
  1489.  
  1490.     if (id == kODNULLID)
  1491.         THROW(kODErrIllegalNullIDInput);
  1492.         
  1493.     frame = (ODFrame*) somSelf->RetrievePersistentObject(ev, id);
  1494.     
  1495.     if (frame == kODNULL) {    
  1496.         
  1497.         su = somSelf->AcquireStorageUnit(ev, id);
  1498.         frame = new ODFrame();
  1499.         
  1500.         if (frame == kODNULL)
  1501.             THROW(kODErrCannotAcquireFrame);
  1502.  
  1503.         // A better way to do this is to let ODFrame::InitFrameFromStorage or
  1504.         // ODPersistentObject::InitPersistentObjectFromStorage to increment the
  1505.         // refcount. In that way, we can always release su here (or even better
  1506.         // make su into a temp obj. - VL        
  1507.         _fPersistentObjects->ReplaceEntry(&id, &frame);
  1508.         frame->InitFrameFromStorage(ev, su);
  1509.         
  1510.         ODStorageUnit *su2 = su;
  1511.         su = kODNULL;                                    // frame owns reference now
  1512.         
  1513.         SetStorageUnitType(ev, _fPermissions, su2, kODFrameObject);
  1514.     }
  1515.     
  1516.     SOM_CATCH_ALL
  1517.         ODSafeReleaseObject(su);
  1518.         if( frame ) WASSERT(frame->GetRefCount(ev)==1);
  1519.         ODSafeReleaseObject(frame);
  1520.     SOM_ENDTRY
  1521.     
  1522.     return frame;
  1523. }
  1524.  
  1525. //------------------------------------------------------------------------------
  1526. // CMDraft: ReleaseFrame
  1527. //------------------------------------------------------------------------------
  1528.  
  1529. SOM_Scope void  SOMLINK CMDraftReleaseFrame(CMDraft *somSelf, Environment *ev,
  1530.         ODFrame* frame)
  1531. {
  1532.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1533.     CMDraftMethodDebug("CMDraft","ReleaseFrame");
  1534.  
  1535.     SOM_CATCH return;
  1536.  
  1537.     somSelf->ReleasePersistentObject(ev, frame);
  1538. }
  1539.  
  1540. //------------------------------------------------------------------------------
  1541. // CMDraft: RemoveFrame
  1542. //------------------------------------------------------------------------------
  1543.  
  1544. SOM_Scope void  SOMLINK CMDraftRemoveFrame(CMDraft *somSelf, Environment *ev,
  1545.         ODFrame* frame)
  1546. {
  1547.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1548.     CMDraftMethodDebug("CMDraft","RemoveFrame");
  1549.  
  1550.     SOM_CATCH return;
  1551.  
  1552.     somSelf->FailIfNotExclusiveWrite(ev);
  1553.     
  1554.     if (frame->GetStorageUnit(ev) == kODNULL)
  1555.         frame->Release(ev);
  1556.     else
  1557.         somSelf->RemovePersistentObject(ev, frame);
  1558. }
  1559.  
  1560. //------------------------------------------------------------------------------
  1561. // CMDraft: ConstructRealPart
  1562. //------------------------------------------------------------------------------
  1563.  
  1564. SOM_Scope ODPart*  SOMLINK CMDraftConstructRealPart(CMDraft *somSelf, Environment *ev,
  1565.         ODStorageUnit* su, ODBoolean isInitPartFromStorage,
  1566.         ODPartWrapper* partWrapper,
  1567.         ODType partType, ODEditor theEditor)
  1568. {
  1569.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1570.     CMDraftMethodDebug("CMDraft","ConstructRealPart");
  1571.  
  1572.     ODPart* part = kODNULL;    ODVolatile(part);
  1573.     ODEditor editorForPart = kODNULL;
  1574.     
  1575.     SOM_TRY
  1576.  
  1577.         ODSession*            session = (ODSession*) _fDocument->GetContainer(ev)->GetStorageSystem(ev)->GetSession(ev);
  1578.         ODBinding*            binding = session->GetBinding(ev);
  1579.     
  1580.         if (theEditor == kODNULL)
  1581.             editorForPart = binding->ChooseEditorForPart(ev, su, partType);
  1582.         else
  1583.         {
  1584.             editorForPart = theEditor;
  1585.             if (_fPermissions != kODDPReadOnly)
  1586.                 ODSetISOStrProp(ev, su, kODPropPreferredEditor, kODEditor, editorForPart);
  1587.         }
  1588.     
  1589.         if (ODISOStrEqual(editorForPart, kODBlackBoxHandlerOfLastResort))
  1590.             part = binding->ConstructNoPart(ev);
  1591.         else {
  1592.             // try to construct a part, if it fails then construct a NoPart instead
  1593.             TRY
  1594.                 part = (ODPart*) ODNewObject(editorForPart);
  1595.             CATCH_ALL
  1596.                 part = binding->ConstructNoPart(ev);
  1597.             ENDTRY
  1598.         }
  1599.     
  1600.         if (part == kODNULL)
  1601.             THROW(kODErrCannotCreatePart);
  1602.             
  1603.         partWrapper->SetRealPart(ev, part, editorForPart);
  1604.     
  1605.         ODID id = su->GetID(ev);
  1606.         _fPersistentObjects->ReplaceEntry(&id, &partWrapper);
  1607.         
  1608.         su->Acquire(ev);                                 //This new reference belongs to the part
  1609.         if (isInitPartFromStorage)
  1610.             partWrapper->InitPartFromStorage(ev, su, partWrapper);
  1611.         else
  1612.             partWrapper->InitPart(ev, su, partWrapper);
  1613.     
  1614.     SOM_CATCH_ALL
  1615.     
  1616.         part = kODNULL;
  1617.  
  1618.         if( ErrorCode() == kODErrCantLoadSOMClass )
  1619.             SetErrorCode(kODErrCannotCreatePart);        // Map to more specific error
  1620.  
  1621.     SOM_ENDTRY    
  1622.     
  1623.     if (editorForPart != theEditor)
  1624.         ODDisposePtr(editorForPart);
  1625.     
  1626.     return part;
  1627. }
  1628.  
  1629. //------------------------------------------------------------------------------
  1630. // CMDraft: ReleaseRealPart
  1631. //------------------------------------------------------------------------------
  1632.  
  1633. SOM_Scope void  SOMLINK CMDraftReleaseRealPart(CMDraft *somSelf, Environment *ev,
  1634.                                                 ODPart* realPart)
  1635. {
  1636.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1637.     CMDraftMethodDebug("CMDraft","ReleaseRealPart");
  1638.  
  1639.     SOM_CATCH return;
  1640.     
  1641.     if (realPart == kODNULL)
  1642.         THROW(kODErrIllegalNullPartInput);
  1643.  
  1644.     if (realPart->GetRefCount(ev) != 0)
  1645.         THROW(kODErrRefCountGreaterThanZero);
  1646.     
  1647.     realPart->ReleaseAll(ev);
  1648.         
  1649.     delete realPart;
  1650. }
  1651.  
  1652. //------------------------------------------------------------------------------
  1653. // CMDraft: DeleteRealPart
  1654. //------------------------------------------------------------------------------
  1655.  
  1656. SOM_Scope void  SOMLINK CMDraftDeleteRealPart(CMDraft *somSelf, Environment *ev,
  1657.                                                 ODPart* realPart)
  1658. {
  1659.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1660.     CMDraftMethodDebug("CMDraft","DeleteRealPart");
  1661.  
  1662.     SOM_CATCH return;
  1663.     
  1664.     if (realPart == kODNULL)
  1665.         THROW(kODErrIllegalNullPartInput);
  1666.  
  1667.     delete realPart;
  1668. }
  1669.  
  1670. //------------------------------------------------------------------------------
  1671. // CMDraft: CreatePart
  1672. //------------------------------------------------------------------------------
  1673.  
  1674. SOM_Scope ODPart*  SOMLINK CMDraftCreatePart(CMDraft *somSelf, Environment *ev,
  1675.         ODType partType, ODEditor optionalEditor)
  1676. {
  1677.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1678.     CMDraftMethodDebug("CMDraft","CreatePart");
  1679.  
  1680.     
  1681.     ODPartWrapper* partWrapper = kODNULL;
  1682.     
  1683.     ODVolatile(partWrapper);
  1684.     SOM_TRY
  1685.     
  1686.         somSelf->FailIfNotExclusiveWrite(ev);
  1687.     
  1688.         TempODStorageUnit su = somSelf->CreateSU(ev, kODNULL, kODPartObject);
  1689.     
  1690.         SetStorageUnitType(ev, _fPermissions, su, kODPartObject);
  1691.         
  1692.         if ( partType != kODNULL )
  1693.         {
  1694.             ODSetISOStrProp(ev, su, kODPropPreferredKind, kODISOStr, partType);
  1695.         }
  1696.     
  1697.         partWrapper = new ODPartWrapper;
  1698.         THROW_IF_NULL(partWrapper, kODErrOutOfMemory);
  1699.         partWrapper->InitPartWrapper(ev);
  1700.         
  1701.         somSelf->ConstructRealPart(ev, su, kODFalse, partWrapper, partType, optionalEditor);
  1702.     
  1703.         somSelf->SetChangedFromPrevFlag(ev, kODTrue);
  1704.         
  1705.     SOM_CATCH_ALL
  1706.     
  1707.         ODSafeReleaseObject(partWrapper);
  1708.         partWrapper = kODNULL;
  1709.         
  1710.     SOM_ENDTRY
  1711.  
  1712.     return partWrapper;
  1713. }
  1714.  
  1715. //------------------------------------------------------------------------------
  1716. // CMDraft: AcquirePart
  1717. //------------------------------------------------------------------------------
  1718.  
  1719. SOM_Scope ODPart*  SOMLINK CMDraftAcquirePart(CMDraft *somSelf, Environment *ev,
  1720.         ODStorageUnitID id)
  1721. {
  1722.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1723.     CMDraftMethodDebug("CMDraft","AcquirePart");
  1724.  
  1725.     ODPart* part = kODNULL;
  1726.     ODPartWrapper* partWrapper = kODNULL;
  1727.     
  1728.     ODVolatile(partWrapper);
  1729.     SOM_TRY
  1730.     
  1731.         if (id == kODNULLID)
  1732.             THROW(kODErrIllegalNullIDInput);
  1733.     
  1734.         part = (ODPart*) somSelf->RetrievePersistentObject(ev, id);
  1735.         if (part == kODNULL) {
  1736.             ODStorageUnit*    su = kODNULL;
  1737.             
  1738.             if (_fStorageUnits->GetValue(&id, &su) != kODFalse)
  1739.                 su->Acquire(ev);
  1740.             else 
  1741.                 su = somSelf->CreateSU(ev, id, kODPartObject);
  1742.             TempODStorageUnit tempSU = su; // ensure it's released
  1743.     
  1744.             partWrapper = new ODPartWrapper;
  1745.             THROW_IF_NULL(partWrapper, kODErrOutOfMemory);
  1746.             partWrapper->InitPartWrapper(ev);
  1747.             
  1748.             somSelf->ConstructRealPart(ev, su, kODTrue, partWrapper, kODNULL,  kODNULL);
  1749.     
  1750.             part = partWrapper;
  1751.     
  1752.             SetStorageUnitType(ev, _fPermissions, su, kODPartObject);
  1753.         }
  1754.     
  1755.     SOM_CATCH_ALL
  1756.         
  1757.         ODSafeReleaseObject(partWrapper);
  1758.         part = kODNULL;
  1759.         
  1760.     SOM_ENDTRY
  1761.     
  1762.     return part;
  1763. }
  1764.  
  1765. //------------------------------------------------------------------------------
  1766. // CMDraft: ReleasePart
  1767. //------------------------------------------------------------------------------
  1768.  
  1769. SOM_Scope void  SOMLINK CMDraftReleasePart(CMDraft *somSelf, Environment *ev,
  1770.         ODPart* part)
  1771. {
  1772.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1773.     CMDraftMethodDebug("CMDraft","ReleasePart");
  1774.  
  1775.     SOM_CATCH return;
  1776.  
  1777.     somSelf->ReleasePersistentObject(ev, part);
  1778. }
  1779.  
  1780. //------------------------------------------------------------------------------
  1781. // CMDraft: RemovePart
  1782. //------------------------------------------------------------------------------
  1783.  
  1784. SOM_Scope void  SOMLINK CMDraftRemovePart(CMDraft *somSelf, Environment *ev,
  1785.         ODPart* part)
  1786. {
  1787.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1788.     CMDraftMethodDebug("CMDraft","RemovePart");
  1789.  
  1790.     SOM_CATCH return;
  1791.  
  1792.     somSelf->RemovePersistentObject(ev, part);
  1793. }
  1794.  
  1795. //------------------------------------------------------------------------------
  1796. // CMDraft: CreateLinkSpec
  1797. //------------------------------------------------------------------------------
  1798.  
  1799. SOM_Scope ODLinkSpec*  SOMLINK CMDraftCreateLinkSpec (CMDraft *somSelf, Environment *ev,
  1800.         ODPart* part,
  1801.         ODByteArray* data)
  1802. {
  1803.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1804.     CMDraftMethodDebug("CMDraft","CreateLinkSpec");
  1805.  
  1806.     ODLinkSpec* ls = kODNULL;
  1807.     
  1808.     ODVolatile(ls);
  1809.     SOM_TRY
  1810.         ls = new ODLinkSpec;
  1811.         THROW_IF_NULL(ls, kODErrOutOfMemory);
  1812.         ls->InitLinkSpec(ev, part, data);
  1813.     SOM_CATCH_ALL
  1814.         ODDeleteObject(ls);
  1815.     SOM_ENDTRY
  1816.         
  1817.     return ls;
  1818. }
  1819.  
  1820. //------------------------------------------------------------------------------
  1821. // CMDraft: CreateLinkSource
  1822. //------------------------------------------------------------------------------
  1823.  
  1824. SOM_Scope ODLinkSource*  SOMLINK CMDraftCreateLinkSource(CMDraft *somSelf, Environment *ev,
  1825.         ODPart* part)
  1826. {
  1827.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1828.     CMDraftMethodDebug("CMDraft","CreateLinkSource");
  1829.  
  1830.     SOM_CATCH return kODNULL;
  1831.  
  1832.     ODStorageUnitID    id;
  1833.     ODLinkSource*    linkSource = kODNULL;
  1834.  
  1835.     somSelf->FailIfNotExclusiveWrite(ev);
  1836.  
  1837.     TempODStorageUnit su = somSelf->CreateSU(ev, kODNULL, kODLinkSource);
  1838.  
  1839.     // The implementation of CMLinkSourceIterator depends on this property being present
  1840.     // in link source storage units and nowhere else.
  1841.     
  1842.     SetStorageUnitType(ev, _fPermissions, su, kODLinkSource);
  1843.     
  1844.     linkSource = new ODLinkSource();
  1845.     THROW_IF_NULL(linkSource,kODErrCannotCreateLink);
  1846.     
  1847.     TempODLink link = kODNULL;
  1848.     TRY
  1849.         link = somSelf->CreateLink(ev);
  1850.     CATCH_ALL
  1851.         linkSource->ReleaseAll(ev);
  1852.         delete linkSource;
  1853.         RERAISE;
  1854.     ENDTRY
  1855.         
  1856.     id = su->GetID(ev);
  1857.     
  1858.     _fPersistentObjects->ReplaceEntry(&id, &linkSource);
  1859.     
  1860.     linkSource->InitLinkSource(ev, su.DontRelease(), part);
  1861.     // ("DontDelete" prevents su from being auto-released by destructor)
  1862.     
  1863.     link->SetLinkSource(ev, linkSource);
  1864.     linkSource->SetLink(ev, link);
  1865.  
  1866.     somSelf->SetChangedFromPrevFlag(ev, kODTrue);
  1867.  
  1868.     return linkSource;
  1869. }
  1870.  
  1871. //------------------------------------------------------------------------------
  1872. // CMDraft: AcquireLinkSource
  1873. //------------------------------------------------------------------------------
  1874.  
  1875. SOM_Scope ODLinkSource*  SOMLINK CMDraftAcquireLinkSource(CMDraft *somSelf, Environment *ev,
  1876.         ODStorageUnitID id)
  1877. {
  1878.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1879.     CMDraftMethodDebug("CMDraft","AcquireLinkSource");
  1880.  
  1881.     SOM_CATCH return kODNULL;
  1882.  
  1883.     if (id == kODNULLID)
  1884.         THROW(kODErrIllegalNullIDInput);
  1885.         
  1886.     ODLinkSource* linkSource = (ODLinkSource*) kODNULL;
  1887.     
  1888.     linkSource = ((ODLinkSource*) somSelf->RetrievePersistentObject(ev, id));
  1889.  
  1890.     if (linkSource == (ODLinkSource*) kODNULL) {    
  1891.         linkSource = new ODLinkSource();
  1892.         if (linkSource == (ODLinkSource*) kODNULL)
  1893.                 THROW(kODErrCannotAcquireLink);
  1894.             
  1895.         ODStorageUnit*    su = (ODStorageUnit*) kODNULL;
  1896.         ODVolatile(su);
  1897.         ODVolatile(id);
  1898.         TRY
  1899.             su = somSelf->AcquireStorageUnit(ev, id);
  1900.             _fPersistentObjects->ReplaceEntry(&id, &linkSource);
  1901.             linkSource->InitLinkSourceFromStorage(ev, su);
  1902.              SetStorageUnitType(ev, _fPermissions, su, kODLinkSource);
  1903.         CATCH_ALL
  1904.             if (su != (ODStorageUnit*) kODNULL) {
  1905.                 _fPersistentObjects->RemoveEntry(&id);
  1906.                 su->Release(ev);
  1907.                 }
  1908.             linkSource->ReleaseAll(ev);
  1909.             delete linkSource;
  1910.             RERAISE;
  1911.         ENDTRY
  1912.         }
  1913.  
  1914.     return linkSource;
  1915. }
  1916.  
  1917. //------------------------------------------------------------------------------
  1918. // CMDraft: RemoveLinkSource
  1919. //------------------------------------------------------------------------------
  1920.  
  1921. SOM_Scope void  SOMLINK CMDraftRemoveLinkSource(CMDraft *somSelf, Environment *ev,
  1922.         ODLinkSource* linkSource)
  1923. {
  1924.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1925.     CMDraftMethodDebug("CMDraft","RemoveLinkSource");
  1926.  
  1927.     SOM_CATCH return;
  1928.  
  1929.     somSelf->FailIfNotExclusiveWrite(ev);
  1930.         
  1931.     somSelf->RemovePersistentObject(ev, linkSource);
  1932. }
  1933.  
  1934. //------------------------------------------------------------------------------
  1935. // CMDraft: CreateLink
  1936. //------------------------------------------------------------------------------
  1937.  
  1938. SOM_Scope ODLink*  SOMLINK CMDraftCreateLink(CMDraft *somSelf, Environment *ev)
  1939. {
  1940.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1941.     CMDraftMethodDebug("CMDraft","CreateLink");
  1942.  
  1943.     SOM_CATCH return kODNULL;
  1944.  
  1945.     ODStorageUnitID    id;
  1946.     ODLink*            link = kODNULL;
  1947.     ODStorageUnit*     su;
  1948.  
  1949.     su = somSelf->CreateSU(ev, kODNULL, kODLink);
  1950.     
  1951.     // The implementation of CMLinkIterator depends on this property being present
  1952.     // in link storage units and nowhere else.
  1953.     SetStorageUnitType(ev, _fPermissions, su, kODLink);
  1954.     
  1955.     link = new ODLink();
  1956.     if (link == kODNULL) 
  1957.     {
  1958.         delete su;
  1959.         THROW(kODErrCannotCreateLink);
  1960.     }
  1961.  
  1962.     id = su->GetID(ev);
  1963.     _fPersistentObjects->ReplaceEntry(&id, &link);
  1964.     
  1965.     link->InitLink(ev, su);
  1966.  
  1967.     somSelf->SetChangedFromPrevFlag(ev, kODTrue);
  1968.  
  1969.     return link;
  1970. }
  1971.  
  1972. //------------------------------------------------------------------------------
  1973. // CMDraft: AcquireLink
  1974. //------------------------------------------------------------------------------
  1975.  
  1976. SOM_Scope ODLink*  SOMLINK CMDraftAcquireLink(CMDraft *somSelf, Environment *ev,
  1977.         ODStorageUnitID id,ODLinkSpec* linkSpec)
  1978. {
  1979.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1980.     CMDraftMethodDebug("CMDraft","AcquireLink");
  1981.  
  1982.     SOM_CATCH return kODNULL;
  1983.     
  1984.     ODLink* link = (ODLink*) kODNULL;
  1985.  
  1986.     if (id != (ODStorageUnitID) kODNULL) {
  1987.         link = ((ODLink*) somSelf->RetrievePersistentObject(ev, id));
  1988.         if (link == (ODLink*) kODNULL) {    
  1989.             link = new ODLink();
  1990.             if (link == kODNULL)
  1991.                 THROW(kODErrCannotAcquireLink);
  1992.             
  1993.             ODStorageUnit*    su = (ODStorageUnit*) kODNULL;
  1994.             ODVolatile(su);
  1995.             ODVolatile(id);
  1996.             TRY
  1997.                 su = somSelf->AcquireStorageUnit(ev, id);
  1998.                 _fPersistentObjects->ReplaceEntry(&id, &link);
  1999.                 link->InitLinkFromStorage(ev, su);
  2000.                  SetStorageUnitType(ev, _fPermissions, su, kODLink);
  2001.             CATCH_ALL
  2002.                 if (su != (ODStorageUnit*) kODNULL) {
  2003.                     _fPersistentObjects->RemoveEntry(&id);
  2004.                     su->Release(ev);
  2005.                     }
  2006.                 link->ReleaseAll(ev);
  2007.                 delete link;
  2008.                 RERAISE;
  2009.             ENDTRY
  2010.             }
  2011.         }
  2012.     else if (linkSpec == (ODLinkSpec*) kODNULL) {
  2013.         THROW(kODErrInsufficientInfoInParams);
  2014.         }
  2015.     else if (linkSpec->FromThisDraft(ev)) {
  2016.         ODPart* part = linkSpec->GetPart(ev);
  2017.         ODByteArray partData = linkSpec->GetPartData(ev);
  2018.         ODVolatile(partData);
  2019.         ODLinkSource* linkSource = kODNULL;
  2020.         ODVolatile(linkSource);
  2021.         TRY
  2022.             linkSource = part->CreateLink(ev, &partData);
  2023.             if ( linkSource != (ODLinkSource*) kODNULL ) {
  2024.                 link = linkSource->GetLink(ev);
  2025.                 if ( link != (ODLink*) kODNULL )
  2026.                     link->Acquire(ev);
  2027.                 }
  2028.         CATCH_ALL
  2029.             DisposeByteArrayStruct(partData);
  2030.             ODReleaseObject(ev, linkSource);
  2031.             RERAISE;
  2032.         ENDTRY
  2033.         DisposeByteArrayStruct(partData);
  2034.         ODReleaseObject(ev, linkSource);
  2035.         }
  2036.     else {
  2037.         // This link spec originated in another document; forward the
  2038.         // AcquireLink call to the originating draft.
  2039.         ODSession* session = _fDocument->GetContainer(ev)->GetStorageSystem(ev)->GetSession(ev);
  2040.         if (session != kODNULL) {
  2041.             ODLinkSource* linkSource = kODNULL;
  2042.             ODVolatile(linkSource);
  2043.             TRY
  2044.                 linkSource = session->GetLinkManager(ev)->CreateLink(ev, somSelf, linkSpec);
  2045.                 if ( linkSource != (ODLinkSource*) kODNULL ) {
  2046.                     link = linkSource->GetLink(ev);
  2047.                     if ( link != (ODLink*) kODNULL )
  2048.                         link->Acquire(ev);
  2049.                     }
  2050.             CATCH_ALL
  2051.                 ODReleaseObject(ev, linkSource);
  2052.                 RERAISE;
  2053.             ENDTRY
  2054.             ODReleaseObject(ev, linkSource);
  2055.             }
  2056.         }
  2057.     return link;
  2058. }
  2059.  
  2060. //------------------------------------------------------------------------------
  2061. // CMDraft: ReleaseLink
  2062. //------------------------------------------------------------------------------
  2063.  
  2064. SOM_Scope void  SOMLINK CMDraftReleaseLink(CMDraft *somSelf, Environment *ev,
  2065.         ODLink* link)
  2066. {
  2067.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2068.     CMDraftMethodDebug("CMDraft","ReleaseLink");
  2069.  
  2070.     SOM_CATCH return;
  2071.  
  2072.     somSelf->ReleasePersistentObject(ev, link);
  2073. }
  2074.  
  2075. //------------------------------------------------------------------------------
  2076. // CMDraft: ReleaseLinkSource
  2077. //------------------------------------------------------------------------------
  2078.  
  2079. SOM_Scope void  SOMLINK CMDraftReleaseLinkSource(CMDraft *somSelf, Environment *ev,
  2080.         ODLinkSource* linkSource)
  2081. {
  2082.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2083.     CMDraftMethodDebug("CMDraft","ReleaseLinkSource");
  2084.  
  2085.     SOM_CATCH return;
  2086.  
  2087.     somSelf->ReleasePersistentObject(ev, linkSource);
  2088. }
  2089.  
  2090. //------------------------------------------------------------------------------
  2091. // CMDraft: RemoveLink
  2092. //------------------------------------------------------------------------------
  2093.  
  2094. SOM_Scope void  SOMLINK CMDraftRemoveLink(CMDraft *somSelf, Environment *ev,
  2095.         ODLink* link)
  2096. {
  2097.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2098.     CMDraftMethodDebug("CMDraft","RemoveLink");
  2099.  
  2100.     SOM_CATCH return;
  2101.  
  2102.     somSelf->FailIfNotExclusiveWrite(ev);
  2103.         
  2104.     somSelf->RemovePersistentObject(ev, link);
  2105. }
  2106.  
  2107. //------------------------------------------------------------------------------
  2108. // CMDraft: GetPersistentObjectID
  2109. //------------------------------------------------------------------------------
  2110.  
  2111. SOM_Scope ODPersistentObjectID  SOMLINK CMDraftGetPersistentObjectID(CMDraft *somSelf, Environment *ev,
  2112.         ODPersistentObject* object,
  2113.         ODObjectType    objectType)
  2114. {
  2115.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2116.     CMDraftMethodDebug("CMDraft","GetPersistentObjectID");
  2117.  
  2118.     SOM_CATCH return kODNULLID;
  2119.  
  2120.     ASSERT(ODISOStrEqual(objectType, kODPartObject) || ODISOStrEqual(objectType, kODFrameObject),
  2121.             kODErrInvalidObjectType);
  2122.         
  2123.     CMStorageUnit* su = (CMStorageUnit*) object->GetStorageUnit(ev);
  2124.     
  2125.     if (su == kODNULL)
  2126.         THROW(kODErrInvalidPersistentObject);
  2127.  
  2128.     return su->GetObjectID(ev);
  2129. }
  2130.  
  2131. //------------------------------------------------------------------------------
  2132. // CMDraft: AcquirePersistentObject
  2133. //------------------------------------------------------------------------------
  2134.  
  2135. SOM_Scope ODPersistentObject* SOMLINK CMDraftAcquirePersistentObject(CMDraft *somSelf, Environment *ev,
  2136.         ODPersistentObjectID objectID,
  2137.         ODObjectType*    objectType)
  2138. {
  2139.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2140.     CMDraftMethodDebug("CMDraft","AcquirePersistentObject");
  2141.     
  2142.     SOM_CATCH return kODNULL;
  2143.     
  2144.     *objectType = kODNULL;
  2145.     ODPersistentObject*    object = kODNULL;
  2146.     ODStorageUnitID    id = kODNULLID;
  2147.     
  2148.     if (objectID == 0)
  2149.         THROW(kODErrIllegalNullIDInput);
  2150.  
  2151.     CMContainer cmContainer = somSelf->GetCMContainer(ev);
  2152.     ODSessionMustHaveCMAllocReserve(cmContainer);
  2153.     
  2154.     CMObject cmObject = CMGetObject(cmContainer, objectID);
  2155.     if (cmObject == kODNULL)
  2156.         THROW(kODErrInvalidPersistentObjectID);
  2157.         
  2158.     if (_fIDList->ObjectExists(cmObject) != kODFalse) {
  2159.         id = _fIDList->GetID(cmObject);
  2160.         CMReleaseObject(cmObject);
  2161.     }
  2162.     else
  2163.         id = _fIDList->Add(cmObject);
  2164.  
  2165.     ODSessionRestoreCMAllocReserve(cmContainer);
  2166.     
  2167.     TempODStorageUnit su = somSelf->AcquireStorageUnit(ev, id);
  2168.     if (su == kODNULL)
  2169.         THROW(kODErrInvalidPersistentObjectID);
  2170.  
  2171.     ODPtr buffer;
  2172.     if ((buffer = ODGetISOStrProp(ev, su, kODPropStorageUnitType, kODISOStr, kODNULL, kODNULL)) != kODNULL)
  2173.     {
  2174.         if (ODISOStrEqual((ODISOStr) buffer, kODPartObject) != kODFalse)
  2175.             object = somSelf->AcquirePart(ev, id);
  2176.         else if (ODISOStrEqual((ODISOStr) buffer, kODFrameObject) != kODFalse)
  2177.             object = somSelf->AcquireFrame(ev, id);
  2178.         else
  2179.             THROW(kODErrInvalidPersistentObjectID);
  2180.         
  2181.         if (object != kODNULL)
  2182.             *objectType = (ODType) buffer;
  2183.         else
  2184.             ODDisposePtr(buffer);        
  2185.     }
  2186.  
  2187.     return object;
  2188. }
  2189.  
  2190. //------------------------------------------------------------------------------
  2191. // CMDraft: ReleaseStorageUnit
  2192. //------------------------------------------------------------------------------
  2193.  
  2194. SOM_Scope ODDraft*  SOMLINK CMDraftReleaseStorageUnit(CMDraft *somSelf, Environment *ev,
  2195.         ODStorageUnitID id)
  2196. {
  2197.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2198.     CMDraftMethodDebug("CMDraft","ReleaseStorageUnit");
  2199.  
  2200.     SOM_CATCH return somSelf;
  2201.  
  2202.     ODStorageUnit*    su = kODNULL;
  2203.     
  2204.     if (! _fStorageUnits->GetValue(&id, &su))
  2205.         THROW(kODErrInvalidStorageUnit);
  2206.     
  2207.     if (su->GetRefCount(ev) != 0)
  2208.         THROW(kODErrRefCountGreaterThanZero);
  2209.         
  2210.     if (_fDraftProperties != kODNULL) {
  2211.         if (id == _fDraftProperties->GetID(ev))
  2212.             _fDraftProperties = kODNULL;
  2213.     }
  2214.     
  2215.     return somSelf;
  2216. }
  2217.  
  2218. //------------------------------------------------------------------------------
  2219. // CMDraft: ~CMDraft
  2220. //------------------------------------------------------------------------------
  2221.  
  2222. SOM_Scope void  SOMLINK CMDraftsomUninit(CMDraft *somSelf)
  2223. {
  2224.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2225.     CMDraftMethodDebug("CMDraft","somUninit");
  2226.  
  2227.     TRY{
  2228.         Environment*    ev = somGetGlobalEnvironment();
  2229.     
  2230. #if ODDebug_DebugRefCount
  2231.         if (somSelf->GetRefCount(ev) != 0)
  2232.             DebugStr("\pRefCount of Draft is not 0 at uninit.");
  2233.         somPrintf("~CMDraft %x RefCount %d EmbeddedCtr %x CMCtr %x\n", 
  2234.                     somSelf,
  2235.                     somSelf->GetRefCount(ev),
  2236.                     somSelf->GetEmbeddedContainer(ev),
  2237.                     somSelf->GetCMContainer(ev));
  2238. #endif
  2239.  
  2240.         somSelf->DeleteCollections(ev);
  2241.     }CATCH_ALL{
  2242.            // Ignore exception
  2243.     }ENDTRY
  2244. }
  2245.  
  2246. //------------------------------------------------------------------------------
  2247. // CMDraft: InitDraft
  2248. //------------------------------------------------------------------------------
  2249.  
  2250. SOM_Scope void  SOMLINK CMDraftInitDraft(CMDraft *somSelf, Environment *ev,
  2251.         ODDocument* document, ODDraftID id, ODDraftPermissions perms)
  2252. {
  2253.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2254.     CMDraftMethodDebug("CMDraft","InitDraft");
  2255.  
  2256.     SOM_CATCH return;
  2257.     
  2258.     /* Moved from somInit. SOM itself sets fields to zero
  2259.     _fChangedFromPrev = kODFalse;
  2260.     
  2261.     _fDocument = kODNULL;
  2262.     _fID = 0;
  2263.     _fPermissions = kODDPNone;
  2264.     _fEmbeddedContainer = kODNULL;
  2265.     _fVersionID = kODTombstonedVersion;
  2266.     _fIsNewDraft = kODFalse;
  2267.     
  2268.     _fExternalized = kODFalse;
  2269.     _fRemoveChangeOnAbort = kODFalse;
  2270.     
  2271.     _fStorageUnits = kODNULL;
  2272.     _fPersistentObjects = kODNULL;
  2273.     
  2274.     _fIDList = kODNULL;
  2275.     _fDraftProperties = kODNULL;
  2276.     
  2277.     _fDestDraft = kODNULL;
  2278.     _fDestFrame = kODNULL;
  2279.     _fClonedSUIDs = kODNULL;
  2280.     _fWeakClonedSUIDs = kODNULL;
  2281.     _fSavedWeakClonedSUIDs = kODNULL;
  2282.     _fLinksToCloneSUIDs = kODNULL;
  2283.     _fCurrentKey = kODNULL;
  2284.     _fLockCount = 0;
  2285.  
  2286.     _fAnyFrameCloned = kODFalse;
  2287.     _fRootPartReused = kODFalse;
  2288.  
  2289.     _fOrigTopVersionDraftID = 0;
  2290.  
  2291.     _fHeap = kDefaultHeapID;
  2292.     */
  2293.     _fVersionID = kODTombstonedVersion; 
  2294.     
  2295.     somSelf->InitRefCntObject(ev); 
  2296.  
  2297. #ifdef ODDebug_VersionList
  2298.     ((CMDocument*) document)->GetVersionList(ev)->Print(">>>Entering InitDraft");
  2299. #endif
  2300.     
  2301.     _fDocument = (CMDocument*) document;
  2302.     _fID = id;
  2303.     _fPermissions = perms;
  2304.  
  2305.     VersionList*    versionList = kODNULL;
  2306.  
  2307.     if (_fDocument == kODNULL)
  2308.         THROW(kODErrIllegalNullDocumentInput);
  2309.         
  2310.     if (_fID == kODNULL) {
  2311.         versionList = _fDocument->GetVersionList(ev);
  2312.         ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  2313.             
  2314.         _fID = versionList->CreateDraft();
  2315.         _fIsNewDraft = kODTrue;
  2316.         _fRemoveChangeOnAbort = kODTrue;
  2317.         
  2318. #if !TestFlushContainer
  2319.         _fDocument->ExternalizeVersionList(ev, kODFalse);
  2320. #endif
  2321.     }
  2322.     
  2323.     somSelf->CreateCollections(ev);
  2324.             
  2325. #if lazyOpen
  2326.     _fExternalized = kODFalse;
  2327. #else
  2328.     if (_fPermissions == kODDPReadOnly)
  2329.         somSelf->OpenVersion(ev);
  2330.     else
  2331.         somSelf->CreateVersion(ev);
  2332. #endif
  2333.         
  2334.     _fHeap = _fDocument->GetHeap(ev);
  2335.  
  2336.  
  2337. #ifdef ODDebug_Unloading_Classes
  2338.     SetOutputMode(kWriteToFile);
  2339. #endif
  2340.  
  2341. #ifdef ODDebug_VersionList
  2342.     _fDocument->GetVersionList(ev)->Print(">>>Exiting InitDraft");
  2343. #endif
  2344. }
  2345.  
  2346. //------------------------------------------------------------------------------
  2347. // CMDraft: Purge
  2348. //------------------------------------------------------------------------------
  2349.  
  2350. SOM_Scope ODSize  SOMLINK CMDraftPurge(CMDraft *somSelf, Environment *ev,
  2351.         ODSize size)
  2352. {
  2353.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2354.     CMDraftMethodDebug("CMDraft","Purge");
  2355.  
  2356.     ODULong    runningTotal = 0; ODVolatile( runningTotal );
  2357.         
  2358.     SOM_TRY
  2359.  
  2360.         OpenHashTableIterator    i(_fPersistentObjects);
  2361.         ODStorageUnitID        id;
  2362.         ODPersistentObject*    object;
  2363.         for (i.First(&id, &object); i.IsNotComplete(); i.Next(&id, &object)) {
  2364.             TRY
  2365.                 runningTotal += object->Purge(ev, size);
  2366.             CATCH_ALL
  2367.             ENDTRY
  2368.  
  2369.             TRY
  2370.                 if (object->GetRefCount(ev) == 0) {
  2371.                     object->ReleaseAll(ev);
  2372.                 }
  2373.             CATCH_ALL
  2374.             ENDTRY
  2375.         }
  2376.         for (i.First(&id, &object); i.IsNotComplete(); i.Next(&id, &object)) {
  2377.             if (object->GetRefCount(ev) == 0) {
  2378.                 i.RemoveCurrent();
  2379.                 delete object;
  2380.             }
  2381.         }
  2382.         // ShrinkToFit() allocates new tables first, and this aggravates
  2383.         // low memory conditions during Purge().
  2384.         // _fPersistentObjects->ShrinkToFit(/*extraSlots*/ 0);
  2385.                 
  2386.         // purge all storage units, but don't release CMObjects 
  2387.         runningTotal += PurgeAllStorageUnits(ev, _fStorageUnits, kODNULL);
  2388.  
  2389.         // dh - call parent Purge method
  2390.         runningTotal += parent_Purge(somSelf, ev, size);
  2391.         
  2392.     SOM_CATCH_ALL
  2393.         WARN("Error %ld trying to purge in CMDraftPurge",ErrorCode());
  2394.         SetErrorCode(kODNoError);        // dh - Eat the exception; Purge should not 
  2395.                                         // propagate it because clients function
  2396.                                         // fine whether memory was purged or not.
  2397.     SOM_ENDTRY
  2398.  
  2399.     return runningTotal;
  2400. }
  2401.  
  2402. //------------------------------------------------------------------------------
  2403. // CMDraft: CreateSU
  2404. //------------------------------------------------------------------------------
  2405.  
  2406. SOM_Scope ODStorageUnit*  SOMLINK CMDraftCreateSU(CMDraft *somSelf, Environment *ev,
  2407.         ODStorageUnitID id, ODType suType)
  2408. {
  2409.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2410.     CMDraftMethodDebug("CMDraft","CreateSU");
  2411.     
  2412.     ODStorageUnit*    su = kODNULL;
  2413.  
  2414.     SOM_TRY
  2415.  
  2416.     CMObject        object = kODNULL;
  2417.     CMContainer        cmContainer = somSelf->GetCMContainer(ev);
  2418.     ODSessionMustHaveCMAllocReserve(cmContainer);
  2419.  
  2420.     ODVolatile(su);
  2421.     ODVolatile(object);
  2422.     TRY    
  2423.         
  2424.         // Create CMObject if necessary
  2425.         
  2426.         if (id == kODNULL) {
  2427.             if ((object = CMNewObject(cmContainer)) == kODNULL)
  2428.                 THROW(kODErrBentoCannotNewObject);
  2429.                 
  2430.             id = _fIDList->Add(object);
  2431.         }        
  2432.  
  2433.         // Create the Storage Unit
  2434.         su = NewCMStorageUnit(somSelf->GetHeap(ev));
  2435.         su->InitStorageUnit(ev, somSelf, id);
  2436.         
  2437.     CATCH_ALL
  2438.         
  2439.         if (object != kODNULL)
  2440.             CMReleaseObject(object);
  2441.             
  2442.         if (su != kODNULL)
  2443.             delete su;
  2444.             
  2445.         if (ErrorCode() == kODErrBentoInvalidObject)
  2446.             THROW(kODErrInvalidID);
  2447.         else
  2448.             RERAISE;
  2449.             
  2450.     ENDTRY
  2451.     ODSessionRestoreCMAllocReserve(cmContainer);
  2452.  
  2453.     // Add Storage Unit to outstanding SU collection
  2454.     
  2455.     _fStorageUnits->ReplaceEntry(&id, &su);
  2456.     
  2457.     SOM_CATCH_ALL
  2458.         su = kODNULL;
  2459.     SOM_ENDTRY
  2460.  
  2461.     return su;
  2462. }
  2463.  
  2464. //------------------------------------------------------------------------------
  2465. // CMDraft: SetChangedFromPrevFlag
  2466. //------------------------------------------------------------------------------
  2467.  
  2468. SOM_Scope void  SOMLINK CMDraftSetChangedFromPrevFlag(CMDraft *somSelf, Environment *ev,
  2469.         ODBoolean changed)
  2470. {
  2471.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2472.     CMDraftMethodDebug("CMDraft","SetChangedFromPrevFlag");
  2473.  
  2474.     if (changed != kODFalse) {
  2475.         SOM_TRY
  2476.             somSelf->FailIfNotExclusiveWrite(ev);
  2477.         SOM_CATCH_ALL
  2478.         SOM_ENDTRY
  2479.     }
  2480.     _fChangedFromPrev = changed;
  2481. }
  2482.  
  2483. static void SetupForUpdatingDraft(Environment* ev,
  2484.                                         CMDocument* localDoc,
  2485.                                         ODVersionID prevVersionID,
  2486.                                         CMValue version)
  2487. {
  2488.     ODBentoContainer*    localContainer = (ODBentoContainer*) localDoc->GetContainer(ev);
  2489.     ODBentoContainer*    container = kODNULL;
  2490.     
  2491.     // check to see whether we need to do a update
  2492.     container = localContainer->GetTargetContainer(ev);
  2493.     
  2494.     if (container != kODNULL) {
  2495.         
  2496.         // get the target document
  2497.         CMDocument*        targetDoc = localContainer->GetTargetDocument(ev);
  2498.         
  2499.         // find its version list
  2500.         VersionList*    versionList = targetDoc->GetVersionList(ev);
  2501.         ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  2502.     
  2503.         // get the latest draft
  2504.         ODDraftID    latestDraftID = versionList->GetLatestDraftID();
  2505.         
  2506.         // get the version id of the latest draft
  2507.         prevVersionID = versionList->GetDraft(latestDraftID);
  2508.     }
  2509.     else {
  2510.         container = localContainer;
  2511.     }
  2512.     // Note: getting/setting refcon's does not allocate memory in Bento:
  2513.     
  2514.     // get the name for indirection
  2515.     ODType prevVersionName = GetVersionNameFromVersionID(prevVersionID, localDoc->GetHeap(ev));
  2516.     
  2517.     // store name so that it can be passed to handler
  2518.     CMSetValueRefCon(version, prevVersionName);
  2519.  
  2520.     // get cmContainer so that we can assess CMSession
  2521.     CMContainer cmContainer = container->GetCMContainer(ev);
  2522.  
  2523.     // Save the outermost container for embedded container creation.
  2524.     ODSessionRefCon* sessionRefCon = (ODSessionRefCon*) CMGetSessionRefCon(cmContainer);
  2525.     sessionRefCon->container = container;
  2526. }
  2527.  
  2528. //------------------------------------------------------------------------------
  2529. // CMDraft: CreateVersion
  2530. //------------------------------------------------------------------------------
  2531.  
  2532. SOM_Scope void  SOMLINK CMDraftCreateVersion(CMDraft *somSelf, Environment *ev)
  2533. {
  2534.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2535.     CMDraftMethodDebug("CMDraft","CreateVersion");
  2536.     
  2537.     SOM_TRY
  2538.  
  2539.     CMContainer                cmContainer = ((ODBentoContainer*) _fDocument->GetContainer(ev))->GetCMContainer(ev);
  2540.     CMObject                versionObject = kODNULL;
  2541.     CMType                    versionNameType = kODNULL;
  2542.     ODType                    versionName = kODNULL;
  2543.     CMProperty                versionNameProperty = kODNULL;
  2544.     CMValue                    versionNameValue = kODNULL;
  2545.     CMType                    versionDataType = kODNULL;
  2546.     CMProperty                versionDataProperty = kODNULL;
  2547.     CMValue                    version = kODNULL;
  2548.     
  2549.     VersionList*            versionList = kODNULL;
  2550.  
  2551.     versionList = _fDocument->GetVersionList(ev);
  2552.     ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  2553.  
  2554.     _fOrigTopVersionDraftID = versionList->GetSameVersionDraftID(_fID);
  2555.     _fPrevVersionID = versionList->GetCurrentVersion(_fID);
  2556.     _fVersionID = versionList->CreateVersion(_fID);
  2557.     
  2558.     ODSessionMustHaveCMAllocReserve(cmContainer);
  2559.  
  2560.     versionObject = CMNewObject(cmContainer);
  2561.     versionNameType = CMRegisterType(cmContainer, kODISOStr);
  2562.  
  2563.     versionName = GetVersionNameFromVersionID(_fVersionID, somSelf->GetHeap(ev));
  2564.     versionNameProperty = CMRegisterProperty(cmContainer, versionName);
  2565.     
  2566.     versionNameValue = CMNewValue(versionObject, versionNameProperty, versionNameType);
  2567.     CMWriteValueData(versionNameValue, "", 0, 1);
  2568.     
  2569.     versionDataType = CMRegisterType(cmContainer, kODEmbeddedContainerType);
  2570.     versionDataProperty = CMRegisterProperty(cmContainer, kODEmbeddedContainerProperty);
  2571.     version = CMNewValue(versionObject, versionDataProperty, versionDataType);
  2572.     if (version == kODNULL)
  2573.         THROW(kODErrCannotCreateDraftVersion);
  2574.     CMWriteValueData(version, "", 0, 0);                /* Make the container manager happy */
  2575.  
  2576.     ODSessionRestoreCMAllocReserve(cmContainer);
  2577.     
  2578.     SetupForUpdatingDraft(ev, _fDocument, _fPrevVersionID, version);
  2579.     
  2580. #ifdef ODDebug_CMDraft
  2581.     ODDocument* tempDoc = somSelf->GetDocument(ev);
  2582.     somPrintf("CreateVersion: CMDocument %x DraftID %d IsNewDraft %d versionID %d prevVersionID %d\n", tempDoc, somSelf->GetID(ev), somSelf->IsNewDraft(ev), _fVersionID, _fPrevVersionID);    
  2583. #endif
  2584.  
  2585.     ODEmbeddedContainerID    containerID;
  2586.     containerID.cmValue = version;
  2587.     containerID.shouldMerge = (somSelf->IsNewDraft(ev) ? kODFalse : kODTrue);
  2588.     ODByteArray*    ba = CreateByteArray(&containerID, sizeof(ODEmbeddedContainerID));
  2589.     _fEmbeddedContainer = (ODEmbeddedContainer*) 
  2590.             _fDocument->GetContainer(ev)->GetStorageSystem(ev)->CreateContainer(ev, kODBentoEmbeddedContainer, ba);
  2591.     DisposeByteArray(ba);
  2592.     
  2593.     if (versionName != kODNULL)
  2594.         ODDisposePtr(versionName);
  2595.  
  2596.     _fExternalized = kODFalse;
  2597.  
  2598.     somSelf->OpenCollections(ev);
  2599.     
  2600.     SOM_CATCH_ALL
  2601.     SOM_ENDTRY
  2602. }
  2603.  
  2604. //------------------------------------------------------------------------------
  2605. // CMDraft: OpenVersion
  2606. //------------------------------------------------------------------------------
  2607.  
  2608. SOM_Scope void  SOMLINK CMDraftOpenVersion(CMDraft *somSelf, Environment *ev)
  2609. {
  2610.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2611.     CMDraftMethodDebug("CMDraft","OpenVersion");
  2612.     
  2613.     SOM_TRY
  2614.  
  2615.     CMContainer                cmContainer = ((ODBentoContainer*) _fDocument->GetContainer(ev))->GetCMContainer(ev);
  2616.     ODType                    versionName = kODNULL;
  2617.     ODType                    oldVersionName = kODNULL;
  2618.     CMType                    versionDataType;
  2619.     CMProperty                versionDataProperty;
  2620.     CMProperty                versionNameProperty;
  2621.     CMObject                versionObject;
  2622.     CMValue                    version;
  2623.  
  2624.     VersionList*            versionList;
  2625.     
  2626.     versionList = _fDocument->GetVersionList(ev);
  2627.     ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  2628.         
  2629.     _fVersionID = versionList->GetCurrentVersion(_fID);
  2630.     _fPrevVersionID = _fVersionID;
  2631.     if (_fVersionID == kODTombstonedVersion)
  2632.         THROW(kODErrDraftHasBeenDeleted);
  2633.     
  2634.     if (_fPermissions == kODDPReadOnly) {
  2635.         ODSessionMustHaveCMAllocReserve(cmContainer);
  2636.     
  2637.         MyDebugStr("**** OpenVersion: kODDPReadOnly.\n");
  2638.         versionDataType = CMRegisterType(cmContainer, kODEmbeddedContainerType);
  2639.         versionDataProperty = CMRegisterProperty(cmContainer, kODEmbeddedContainerProperty);
  2640.         
  2641.         versionName = GetVersionNameFromVersionID(_fVersionID, somSelf->GetHeap(ev));
  2642.         versionNameProperty = CMRegisterProperty(cmContainer, versionName);
  2643.         
  2644.         versionObject = CMGetNextObjectWithProperty(cmContainer, kODNULL, versionNameProperty);
  2645.         version = CMUseValue(versionObject, versionDataProperty, versionDataType);
  2646.     
  2647.         CMSetValueRefCon(version, kODNULL);
  2648.         
  2649.         // Save the outermost container for embedded container creation.
  2650.         ODSessionRefCon* sessionRefCon = (ODSessionRefCon*) CMGetSessionRefCon(cmContainer);
  2651.         sessionRefCon->container = _fDocument->GetContainer(ev);
  2652.     
  2653. #ifdef ODDebug_CMDraft
  2654.     ODDocument* tempDoc = somSelf->GetDocument(ev);
  2655.     somPrintf("OpenVersion: CMDocument %x DraftID %d IsNewDraft %d versionID %d prevVersionID %d\n", tempDoc, somSelf->GetID(ev), somSelf->IsNewDraft(ev), _fVersionID, _fPrevVersionID);    
  2656. #endif
  2657.         ODEmbeddedContainerID    containerID;
  2658.         containerID.cmValue = version;
  2659.         containerID.shouldMerge = kODFalse;
  2660.         ODByteArray*    ba = CreateByteArray(&containerID, sizeof(ODEmbeddedContainerID));
  2661.         _fEmbeddedContainer = (ODEmbeddedContainer*)
  2662.             _fDocument->GetContainer(ev)->GetStorageSystem(ev)->AcquireContainer(ev, kODBentoEmbeddedContainer, ba);
  2663.         DisposeByteArray(ba);
  2664.     
  2665.         if (versionName != kODNULL)
  2666.             ODDisposePtr(versionName);
  2667.         if (oldVersionName != kODNULL)
  2668.             ODDisposePtr(oldVersionName);
  2669.             
  2670.         ODSessionRestoreCMAllocReserve(cmContainer);
  2671.  
  2672.         somSelf->OpenCollections(ev);
  2673.     }
  2674.     else
  2675.         THROW(kODErrInvalidPermissions);
  2676.     
  2677.     SOM_CATCH_ALL
  2678.     SOM_ENDTRY
  2679. }
  2680.  
  2681. //------------------------------------------------------------------------------
  2682. // CMDraft: CloseVersion
  2683. //------------------------------------------------------------------------------
  2684.  
  2685. SOM_Scope void  SOMLINK CMDraftCloseVersion(CMDraft *somSelf, Environment *ev)
  2686. {
  2687.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2688.     CMDraftMethodDebug("CMDraft","CloseVersion");
  2689.     
  2690.     SOM_TRY
  2691.  
  2692. #ifdef ODDebug_CMDraft
  2693.     ODDocument* tempDoc = somSelf->GetDocument(ev);
  2694.     somPrintf("CloseVersion: CMDocument %x DraftID %d versionID %d Permission %d\n", tempDoc, somSelf->GetID(ev), _fVersionID, _fPermissions);    
  2695. #endif
  2696.  
  2697.  
  2698.     if (_fPermissions == kODDPExclusiveWrite) {
  2699.         VersionList*    versionList = kODNULL;
  2700.  
  2701.         versionList = _fDocument->TestAndGetVersionList(ev);
  2702.         ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  2703.     
  2704.         if (versionList->IsBelow(_fOrigTopVersionDraftID, versionList->GetSameVersionDraftID(_fID)))
  2705.             _fEmbeddedContainer->SetMergeFlag(ev, kODFalse);
  2706.         somSelf->CloseCollections(ev);
  2707.     }
  2708.     else {
  2709.         somSelf->DeleteCollections(ev);
  2710.         somSelf->CreateCollections(ev);
  2711.     }
  2712.     
  2713.     if (_fEmbeddedContainer != kODNULL) {
  2714.         _fEmbeddedContainer->Release(ev);
  2715.         _fEmbeddedContainer = kODNULL;
  2716.     }
  2717.     
  2718.     _fIsNewDraft = kODFalse;
  2719.     
  2720.     SOM_CATCH_ALL
  2721.     SOM_ENDTRY
  2722. }
  2723.  
  2724. //------------------------------------------------------------------------------
  2725. // CMDraft: DestroyVersion
  2726. //------------------------------------------------------------------------------
  2727.  
  2728. SOM_Scope void  SOMLINK CMDraftDestroyVersion(CMDraft *somSelf, Environment *ev)
  2729. {
  2730.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2731.     CMDraftMethodDebug("CMDraft","DestroyVersion");
  2732.     
  2733. #ifdef ODDebug_CMDraft
  2734.     ODDocument* tempDoc = somSelf->GetDocument(ev);
  2735.     somPrintf("Destroy Version: CMDocument %x DraftID %d versionID %d Permission %d\n", tempDoc, somSelf->GetID(ev), _fVersionID, _fPermissions);    
  2736. #endif
  2737.     
  2738.     if (_fPermissions == kODDPExclusiveWrite) {
  2739.         SOM_TRY
  2740.     
  2741.         somSelf->DeleteCollections(ev);
  2742.         somSelf->CreateCollections(ev);
  2743.     
  2744.         if (_fEmbeddedContainer != kODNULL) {
  2745.             _fEmbeddedContainer->Abort(ev);
  2746.             CMObject        parentObject = kODNULL;
  2747.             ODByteArray     ba = _fEmbeddedContainer->GetID(ev);
  2748.             CMValue parentValue = *((CMValue*) ba._buffer);
  2749.             ODDisposePtr(ba._buffer);
  2750.  
  2751.             CMContainer cmContainer = somSelf->GetCMContainer(ev);
  2752.             ODSessionMustHaveCMAllocReserve(cmContainer);
  2753.             
  2754.             CMGetValueInfo(parentValue, kODNULL, &parentObject,
  2755.                             kODNULL, kODNULL, kODNULL);
  2756.             CMDeleteValue(parentValue);
  2757.             CMDeleteObject(parentObject);
  2758.  
  2759.             ODSessionRestoreCMAllocReserve(cmContainer);
  2760.             
  2761.             _fEmbeddedContainer->Release(ev);
  2762.             _fEmbeddedContainer = kODNULL;
  2763.         }
  2764.         
  2765.         SOM_CATCH_ALL
  2766.         SOM_ENDTRY
  2767.     }
  2768. }
  2769.  
  2770. //------------------------------------------------------------------------------
  2771. // CMDraft: FlushVersion
  2772. //------------------------------------------------------------------------------
  2773.  
  2774. SOM_Scope void  SOMLINK CMDraftFlushVersion(CMDraft *somSelf, Environment *ev)
  2775. {
  2776.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2777.     CMDraftMethodDebug("CMDraft","FlushVersion");
  2778.  
  2779. }
  2780.  
  2781. //------------------------------------------------------------------------------
  2782. // CMDraft: Reinitialize
  2783. //------------------------------------------------------------------------------
  2784.  
  2785. SOM_Scope void  SOMLINK CMDraftReinitialize(CMDraft *somSelf, Environment *ev,
  2786.         ODDraftPermissions perms)
  2787. {
  2788.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2789.     CMDraftMethodDebug("CMDraft","Reinitialize");
  2790.     
  2791.     SOM_TRY
  2792.  
  2793.     if ((perms == kODDPExclusiveWrite) &&
  2794.         (_fEmbeddedContainer != kODNULL) &&
  2795.         (_fEmbeddedContainer->GetUseMode(ev) & kCMReading)) {
  2796.         MyDebugStr("Reinitialize.\n");
  2797.         THROW(kODErrInvalidPermissions);
  2798.     }
  2799.     
  2800.     // Close this version first
  2801.     
  2802.     // somSelf->CloseVersion(ev);
  2803.     
  2804.     // Set the permissions
  2805.     
  2806.     _fPermissions = perms;
  2807.  
  2808.     // Open or create a new version
  2809.  
  2810.     if (_fEmbeddedContainer == kODNULL) {
  2811. #if lazyOpen
  2812.         _fExternalized = kODFalse;
  2813. #else
  2814.         if (_fPermissions == kODDPReadOnly)
  2815.             somSelf->OpenVersion(ev);
  2816.         else
  2817.             somSelf->CreateVersion(ev);
  2818. #endif
  2819.     }
  2820.     
  2821.     //_fDocument->Reopen(ev);
  2822.     
  2823.     SOM_CATCH_ALL
  2824.     SOM_ENDTRY
  2825. }
  2826.  
  2827. //------------------------------------------------------------------------------
  2828. // CMDraft: Open
  2829. //------------------------------------------------------------------------------
  2830.  
  2831. SOM_Scope void  SOMLINK CMDraftOpen(CMDraft *somSelf, Environment *ev)
  2832. {
  2833.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2834.     CMDraftMethodDebug("CMDraft","Open");
  2835.  
  2836.     SOM_CATCH return;
  2837.  
  2838.     if (_fEmbeddedContainer == kODNULL) {
  2839. #if lazyOpen
  2840.         _fExternalized = kODFalse;
  2841. #else
  2842.         if (_fPermissions == kODDPReadOnly)
  2843.             somSelf->OpenVersion(ev);
  2844.         else
  2845.             somSelf->CreateVersion(ev);
  2846. #endif
  2847.     }
  2848. }
  2849.  
  2850. #pragma segment CMDraft2
  2851.  
  2852. //------------------------------------------------------------------------------
  2853. // CMDraft: Close
  2854. //------------------------------------------------------------------------------
  2855.  
  2856. SOM_Scope void  SOMLINK CMDraftClose(CMDraft *somSelf, Environment *ev)
  2857. {
  2858.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2859.     CMDraftMethodDebug("CMDraft","Close");
  2860.  
  2861.     SOM_CATCH return;
  2862.  
  2863. #if ODDebug_Drafts
  2864.     somPrintf("CMDraftClose: %d\n", somSelf->GetID(ev));
  2865. #endif
  2866.  
  2867. #if lazyOpen
  2868.     if (_fEmbeddedContainer != kODNULL) {
  2869.  
  2870.         CMContainer cmContainer = somSelf->GetCMContainer(ev);
  2871.         ODSessionMustHaveCMAllocReserve(cmContainer);
  2872.         // AcquireDraftPropertiesObject() makes CM calls:
  2873.  
  2874.         CMObject draftPropertiesObject = AcquireDraftPropertiesObject(somSelf->GetCMContainer(ev));
  2875.         if (draftPropertiesObject == kODNULL)
  2876.             THROW(kODErrNoDraftProperties);
  2877.         
  2878.         CMKeepObject(draftPropertiesObject);
  2879.         
  2880.         ODSessionRestoreCMAllocReserve(cmContainer);
  2881.         
  2882.         somSelf->CloseVersion(ev);
  2883.     }
  2884. #else
  2885.     somSelf->CloseVersion(ev);
  2886. #endif
  2887. }
  2888.  
  2889. //------------------------------------------------------------------------------
  2890. // CMDraft: Abort
  2891. //------------------------------------------------------------------------------
  2892.  
  2893. SOM_Scope void  SOMLINK CMDraftAbort(CMDraft *somSelf, Environment *ev)
  2894. {
  2895.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2896.     CMDraftMethodDebug("CMDraft","Abort");
  2897.  
  2898.     SOM_TRY
  2899.  
  2900.     if (_fPermissions == kODDPReadOnly)
  2901.         THROW(kODErrInvalidPermissions);
  2902.  
  2903.     if (_fDraftProperties != kODNULL) {
  2904.         _fDraftProperties->Release(ev);
  2905.         _fDraftProperties = kODNULL;
  2906.     }
  2907.  
  2908. #if TestFlushContainer
  2909.     if (_fRemoveChangeOnAbort) {
  2910.         VersionList*    versionList = kODNULL;
  2911.         
  2912.         versionList = _fDocument->TestAndGetVersionList(ev);
  2913.         ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  2914.     
  2915.         TRY
  2916.             if (versionList->Exists(_fID) != kODFalse)
  2917.                 versionList->RemoveChanges(_fID);
  2918.             
  2919.         CATCH_ALL
  2920.         
  2921.             _fDocument->ReleaseVersionList(ev);
  2922.             RERAISE;
  2923.     
  2924.         ENDTRY
  2925.     }
  2926. #else
  2927.     _fDocument->InternalizeVersionList(ev);
  2928. #endif
  2929.     somSelf->DestroyVersion(ev);
  2930.     //    _fDocument->Reopen(ev);
  2931.     
  2932.     SOM_CATCH_ALL
  2933.     SOM_ENDTRY
  2934. }
  2935.  
  2936. //------------------------------------------------------------------------------
  2937. // CMDraft: Flush
  2938. //------------------------------------------------------------------------------
  2939.  
  2940. SOM_Scope void  SOMLINK CMDraftFlush(CMDraft *somSelf, Environment *ev)
  2941. {
  2942.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2943.     CMDraftMethodDebug("CMDraft","Flush");
  2944.  
  2945.     if (_fPermissions == kODDPExclusiveWrite) {
  2946.         SOM_TRY
  2947.             somSelf->FlushVersion(ev);
  2948.         SOM_CATCH_ALL
  2949.         SOM_ENDTRY
  2950.     }
  2951. }
  2952.  
  2953.  
  2954. //------------------------------------------------------------------------------
  2955. // CMDraft: IsNewDraft
  2956. //------------------------------------------------------------------------------
  2957.  
  2958. SOM_Scope ODBoolean  SOMLINK CMDraftIsNewDraft(CMDraft *somSelf, Environment *ev)
  2959. {
  2960.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2961.     CMDraftMethodDebug("CMDraft","IsNewDraft");
  2962.  
  2963.     return _fIsNewDraft;
  2964. }
  2965.  
  2966. //------------------------------------------------------------------------------
  2967. // CMDraft: GetEmbeddedContainer
  2968. //------------------------------------------------------------------------------
  2969.  
  2970. SOM_Scope ODEmbeddedContainer*  SOMLINK CMDraftGetEmbeddedContainer(CMDraft *somSelf, Environment *ev)
  2971. {
  2972.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2973.     CMDraftMethodDebug("CMDraft","GetEmbeddedContainer");
  2974.  
  2975. #if lazyOpen
  2976.     SOM_TRY
  2977.     if (_fEmbeddedContainer == kODNULL) {
  2978.         if (_fPermissions == kODDPReadOnly)
  2979.             somSelf->OpenVersion(ev);
  2980.         else
  2981.             somSelf->CreateVersion(ev);
  2982.     }
  2983.     SOM_CATCH_ALL
  2984.     SOM_ENDTRY
  2985. #endif
  2986.  
  2987.     return _fEmbeddedContainer;
  2988. }
  2989.  
  2990. //------------------------------------------------------------------------------
  2991. // CMDraft: GetCMContainer
  2992. //------------------------------------------------------------------------------
  2993.  
  2994. SOM_Scope CMContainer  SOMLINK CMDraftGetCMContainer(CMDraft *somSelf, Environment *ev)
  2995. {
  2996.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2997.     CMDraftMethodDebug("CMDraft","GetCMContainer");
  2998.     
  2999.     SOM_TRY
  3000.  
  3001. #if lazyOpen
  3002.     if (_fEmbeddedContainer == kODNULL) {
  3003.         if (_fPermissions == kODDPReadOnly)
  3004.             somSelf->OpenVersion(ev);
  3005.         else
  3006.             somSelf->CreateVersion(ev);
  3007.     }
  3008. #endif
  3009.  
  3010.     if (_fEmbeddedContainer == kODNULL)
  3011.         THROW(kODErrCannotGetDraftVersion);
  3012.     return _fEmbeddedContainer->GetCMContainer(ev);
  3013.     
  3014.     SOM_CATCH_ALL
  3015.     SOM_ENDTRY
  3016.     return kODNULL;
  3017. }
  3018.  
  3019. //------------------------------------------------------------------------------
  3020. // AcquireDraftPropertiesObject
  3021. //------------------------------------------------------------------------------
  3022.  
  3023. // Callers must ODSessionMustHaveCMAllocReserve() first:
  3024.  
  3025. static CMObject AcquireDraftPropertiesObject(CMContainer container)
  3026. {
  3027.     CMObject        draftPropertiesObject = kODNULL;
  3028.     CMType            rootSUType;
  3029.     CMProperty        rootSUProp;
  3030.     CMValue            rootSU;
  3031.     
  3032.     CMContainerModeFlags    openMode;
  3033.  
  3034.     if ((rootSUType = CMRegisterType(container, kODStorageUnitType)) == kODNULL)
  3035.         THROW(kODErrBentoInvalidType);
  3036.     if ((rootSUProp = CMRegisterProperty(container, kODPropRootSU)) == kODNULL)
  3037.         THROW(kODErrBentoInvalidProperty);
  3038.     draftPropertiesObject = CMGetNextObjectWithProperty(container, kODNULL, rootSUProp);
  3039.     
  3040.     if (draftPropertiesObject == kODNULL) {
  3041.         
  3042.         CMGetContainerInfo(container, kODNULL, kODNULL, kODNULL, kODNULL, &openMode);
  3043.         if (openMode == kCMReading)
  3044.             return kODNULL;
  3045.         
  3046.         draftPropertiesObject = CMNewObject(container);
  3047.  
  3048.         if ((rootSU = CMNewValue(draftPropertiesObject, rootSUProp, rootSUType)) == kODNULL)
  3049.             THROW(kODErrBentoCannotNewValue);
  3050.         CMWriteValueData(rootSU, "", 0, 0);
  3051.     }
  3052.     
  3053.     return draftPropertiesObject;
  3054. }
  3055.  
  3056. //------------------------------------------------------------------------------
  3057. // GetVersionNameFromVersionID
  3058. //------------------------------------------------------------------------------
  3059.  
  3060. static ODType GetVersionNameFromVersionID(ODVersionID id, ODMemoryHeapID heapID)
  3061. {
  3062.     ODSByte*    versionName = kODNULL;
  3063.     ODSByte    cString[kMaxStringSize];
  3064.         
  3065.     if (id != 0) {
  3066.         itoa(id, cString);
  3067.         versionName = (ODSByte*) ODNewPtr(strlen(kODVersionNamePrefix) + strlen(cString) + 1, heapID);
  3068.         strcpy(versionName, kODVersionNamePrefix);
  3069.         strcat(versionName, cString);
  3070.     }
  3071.     return versionName;
  3072. }
  3073.  
  3074. //------------------------------------------------------------------------------
  3075. // CMDraft: RetrievePersistentObject
  3076. //------------------------------------------------------------------------------
  3077.  
  3078. SOM_Scope ODPersistentObject*  SOMLINK CMDraftRetrievePersistentObject(CMDraft *somSelf, Environment *ev,
  3079.         ODStorageUnitID id)
  3080. {
  3081.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3082.     CMDraftMethodDebug("CMDraft","RetrievePersistentObject");
  3083.  
  3084.     ODPersistentObject*    object = kODNULL;
  3085.     
  3086.     SOM_TRY
  3087.     
  3088.     if (_fPersistentObjects->GetValue(&id, &object))
  3089.         object->Acquire(ev);
  3090.     
  3091.     SOM_CATCH_ALL
  3092.     SOM_ENDTRY
  3093.     return object;
  3094. }
  3095.  
  3096. //------------------------------------------------------------------------------
  3097. // CMDraft: ReleasePersistentObject
  3098. //------------------------------------------------------------------------------
  3099.  
  3100. SOM_Scope void  SOMLINK CMDraftReleasePersistentObject(CMDraft *somSelf, Environment *ev,
  3101.         ODPersistentObject* object)
  3102. {
  3103. //  CMDraftData *somThis = CMDraftGetData(somSelf);
  3104.     CMDraftMethodDebug("CMDraft","ReleasePersistentObject");
  3105.     
  3106.     SOM_TRY
  3107.     
  3108.     if (object->GetRefCount(ev) != 0)
  3109.         THROW(kODErrRefCountGreaterThanZero);
  3110.     
  3111.     SOM_CATCH_ALL
  3112.     SOM_ENDTRY
  3113. }
  3114.  
  3115. //------------------------------------------------------------------------------
  3116. // CMDraft: RemovePersistentObject
  3117. //------------------------------------------------------------------------------
  3118.  
  3119. SOM_Scope void  SOMLINK CMDraftRemovePersistentObject(CMDraft *somSelf, Environment *ev,
  3120.         ODPersistentObject* object)
  3121. {
  3122.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3123.     CMDraftMethodDebug("CMDraft","RemovePersistentObject");
  3124.     
  3125.     SOM_TRY
  3126.  
  3127.     ODStorageUnit*        su = object->GetStorageUnit(ev);
  3128.     ODStorageUnitID        id = object->GetID(ev);
  3129.     CMObject            cmObject = kODNULL;
  3130.     
  3131.     if (id == kODNULLID)
  3132.         THROW(kODErrInvalidPersistentObjectID);
  3133.         
  3134.     object->Release(ev);
  3135.  
  3136.     if (object->GetRefCount(ev) != 0)
  3137.         THROW(kODErrRefCountGreaterThanZero);
  3138.  
  3139.     if ((su != kODNULL) && (su->GetRefCount(ev) != 1))
  3140.         THROW(kODErrRefCountNotEqualOne);
  3141.  
  3142.     object->ReleaseAll(ev);
  3143.  
  3144.     _fPersistentObjects->RemoveEntry(&id);
  3145.     delete object;
  3146.     
  3147.     _fStorageUnits->RemoveEntry(&id);
  3148.     delete su;
  3149.  
  3150.     if (_fIDList->Exists(id) != kODFalse) {
  3151.         cmObject = (CMObject) _fIDList->Get(id);
  3152.         _fIDList->Remove(id);
  3153.  
  3154.         CMContainer cmContainer = somSelf->GetCMContainer(ev);
  3155.         ODSessionMustHaveCMAllocReserve(cmContainer);
  3156.  
  3157.         if (cmObject != kODNULL)
  3158.             CMDeleteObject(cmObject);
  3159.  
  3160.         ODSessionRestoreCMAllocReserve(cmContainer);
  3161.     }
  3162.  
  3163.     somSelf->SetChangedFromPrevFlag(ev, kODTrue);
  3164.     
  3165.     SOM_CATCH_ALL
  3166.     SOM_ENDTRY
  3167. }
  3168.  
  3169. //------------------------------------------------------------------------------
  3170. // CMDraft: CreateCollections
  3171. //------------------------------------------------------------------------------
  3172.  
  3173. SOM_Scope void  SOMLINK CMDraftCreateCollections(CMDraft *somSelf, Environment *ev)
  3174. {
  3175.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3176.     CMDraftMethodDebug("CMDraft","CreateCollections");
  3177.     
  3178.     SOM_TRY
  3179.  
  3180.     ODMemoryHeapID heap = somSelf->GetHeap(ev);
  3181.  
  3182.     _fPersistentObjects = new(heap) 
  3183.         OpenHashTable(OpenHashTable::StdEqual,
  3184.                       OpenHashTable::StdHash, heap);
  3185.     _fPersistentObjects->Initialize(kODInitialNumEntries,
  3186.                                     sizeof(ODStorageUnitID),
  3187.                                     sizeof(ODPersistentObject*));
  3188.  
  3189.     _fStorageUnits = new(heap) 
  3190.         OpenHashTable(OpenHashTable::StdEqual,
  3191.                       OpenHashTable::StdHash, heap);
  3192.     _fStorageUnits->Initialize(kODInitialNumEntries,
  3193.                                sizeof(ODStorageUnitID),
  3194.                                sizeof(ODStorageUnit*));
  3195.  
  3196.     _fIDList = new(somSelf->GetHeap(ev)) IDList;
  3197.     _fIDList->Initialize();
  3198.     
  3199.     SOM_CATCH_ALL
  3200.     SOM_ENDTRY
  3201. }
  3202.  
  3203. //------------------------------------------------------------------------------
  3204. // CMDraft: DeleteCollections
  3205. //------------------------------------------------------------------------------
  3206.  
  3207. SOM_Scope void  SOMLINK CMDraftDeleteCollections(CMDraft *somSelf, Environment *ev)
  3208. {
  3209.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3210.     CMDraftMethodDebug("CMDraft","DeleteCollections");
  3211.     
  3212.     SOM_TRY
  3213.  
  3214.     if (_fDraftProperties != kODNULL)
  3215.     {
  3216.         _fDraftProperties->Release(ev);
  3217.         _fDraftProperties = kODNULL;
  3218.     }
  3219.     if (_fPersistentObjects != kODNULL) {
  3220.         ODStorageUnitID        id;
  3221.         ODPersistentObject*    object;
  3222.         OpenHashTableIterator    iter(_fPersistentObjects);
  3223.         
  3224.         for (iter.First(&id, &object); iter.IsNotComplete(); iter.Next(&id, &object)) {
  3225.             if (object != kODNULL) {
  3226.                 SOM_TRY
  3227.                     object->ReleaseAll(ev);
  3228.                 SOM_CATCH_ALL
  3229.                     WARN("Exception thrown by object %x ID %x error %d\n", object, object->GetID(ev), ErrorCode());
  3230.                 SOM_ENDTRY
  3231.             }
  3232.         }
  3233.         
  3234.         for (iter.First(&id, &object); iter.IsNotComplete(); iter.Next(&id, &object)) {
  3235.             if (object != kODNULL) {
  3236.                 delete object;
  3237.             }
  3238.         }
  3239.         delete _fPersistentObjects;
  3240.         _fPersistentObjects = kODNULL;
  3241.     }
  3242.  
  3243.     if (_fStorageUnits != kODNULL) {
  3244.         ODStorageUnitID        id;
  3245.         ODStorageUnit*            su;
  3246.         OpenHashTableIterator    iter(_fStorageUnits);
  3247.         for (iter.First(&id, &su); iter.IsNotComplete(); iter.Next(&id, &su)) {
  3248.             if (su != kODNULL) {
  3249.                 delete su;
  3250.             }
  3251.         }
  3252.         delete _fStorageUnits;
  3253.         _fStorageUnits = kODNULL;
  3254.         _fDraftProperties = kODNULL;
  3255.     }
  3256.     
  3257.     ODDeleteObject(_fIDList);
  3258.     
  3259.     SOM_CATCH_ALL
  3260.     SOM_ENDTRY
  3261. }
  3262.  
  3263. //------------------------------------------------------------------------------
  3264. // CMDraft: ExternalizeCollections
  3265. //------------------------------------------------------------------------------
  3266.  
  3267. SOM_Scope void  SOMLINK CMDraftExternalizeCollections(CMDraft *somSelf, Environment *ev)
  3268. {
  3269.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3270.     CMDraftMethodDebug("CMDraft","ExternalizeCollections");
  3271.     
  3272.     SOM_TRY
  3273.  
  3274.     ODID                    id;
  3275.     ODStorageUnit*            su;
  3276.  
  3277.     OpenHashTableIterator    persistentObjects(_fPersistentObjects);
  3278.     ODPersistentObject*    object;
  3279.     
  3280.     for (persistentObjects.First(&id, &object);
  3281.             persistentObjects.IsNotComplete();
  3282.             persistentObjects.Next(&id, &object)) {
  3283.         // Temporarily bump the refcount to make sure that the object is
  3284.         // in a valid state.
  3285.         object->Acquire(ev);
  3286.         TempODRefCntObject tempObject = object; // ensure it's released
  3287.         su = object->GetStorageUnit(ev);
  3288.         if ((su != kODNULL) && (su->Exists(ev, kODNULL, kODNULL, 0) != kODFalse))
  3289.         object->Externalize(ev);
  3290.     }
  3291.  
  3292.     OpenHashTable            suCollection(*_fStorageUnits);
  3293.     suCollection.InitAndCopyFrom(*_fStorageUnits);
  3294.     OpenHashTableIterator    storageUnits(&suCollection);
  3295.  
  3296.     for (storageUnits.First(&id, &su);
  3297.             storageUnits.IsNotComplete();
  3298.             storageUnits.Next(&id, &su)) {
  3299.         // Temporarily bump the refcount to make sure that the object is
  3300.         // in a valid state.
  3301.         su->Acquire(ev);
  3302.         TempODStorageUnit tempSU = su; // ensure it's released
  3303.         if (su->Exists(ev, kODNULL, kODNULL, 0) != kODFalse)
  3304.             su->Externalize(ev);
  3305.     }
  3306.     
  3307.     SOM_CATCH_ALL
  3308.     SOM_ENDTRY
  3309. }
  3310.  
  3311. //------------------------------------------------------------------------------
  3312. // CMDraft: CloseCollections
  3313. //------------------------------------------------------------------------------
  3314.  
  3315. SOM_Scope void  SOMLINK CMDraftCloseCollections(CMDraft *somSelf, Environment *ev)
  3316. {
  3317.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3318.     CMDraftMethodDebug("CMDraft","CloseCollections");
  3319.     
  3320.     SOM_TRY
  3321.     
  3322.     somSelf->FailIfNotExclusiveWrite(ev);
  3323.     
  3324.     somSelf->Purge(ev, 0);
  3325.     PurgeAllStorageUnits(ev, _fStorageUnits, _fIDList); // purge SU, relase CMObjects
  3326.     
  3327.     SOM_CATCH_ALL
  3328.     SOM_ENDTRY
  3329. }
  3330.  
  3331. //------------------------------------------------------------------------------
  3332. // CMDraft: OpenCollections
  3333. //------------------------------------------------------------------------------
  3334.  
  3335. SOM_Scope void  SOMLINK CMDraftOpenCollections(CMDraft *somSelf, Environment *ev)
  3336. {
  3337.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3338.     CMDraftMethodDebug("CMDraft","OpenCollections");
  3339.     
  3340.     SOM_TRY
  3341.  
  3342.     OpenHashTableIterator    storageUnits(_fStorageUnits);
  3343.     
  3344.     ODID                    id;
  3345.     ODStorageUnit*            su;
  3346.  
  3347.     for (storageUnits.First(&id, &su);
  3348.             storageUnits.IsNotComplete();
  3349.             storageUnits.Next(&id, &su)) {
  3350.         su->Internalize(ev);
  3351.     }
  3352.     
  3353.     SOM_CATCH_ALL
  3354.     SOM_ENDTRY
  3355. }
  3356.  
  3357. //------------------------------------------------------------------------------
  3358. // CMDraft: AreEmptyCollections
  3359. //------------------------------------------------------------------------------
  3360.  
  3361. SOM_Scope ODBoolean  SOMLINK CMDraftAreEmptyCollections(CMDraft *somSelf, Environment *ev)
  3362. {
  3363.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3364.     CMDraftMethodDebug("CMDraft","AreEmptyCollections");
  3365.     
  3366.     SOM_TRY
  3367.  
  3368.     OpenHashTableIterator    storageUnits(_fStorageUnits);
  3369.     OpenHashTableIterator    persistentObjects(_fPersistentObjects);
  3370.     ODID                    id;
  3371.     ODPersistentObject*    object;
  3372.     ODStorageUnit*            su;
  3373.     
  3374.     for (persistentObjects.First(&id, &object);
  3375.             persistentObjects.IsNotComplete();
  3376.             persistentObjects.Next(&id, &object)) {
  3377.         if (object->GetRefCount(ev) > 0)
  3378.             return kODFalse;
  3379.     }
  3380.  
  3381.     for (storageUnits.First(&id, &su); storageUnits.IsNotComplete(); storageUnits.Next(&id, &su)) {
  3382.         if (su->GetRefCount(ev) > 0)
  3383.             return kODFalse;
  3384.     }
  3385.     
  3386.     SOM_CATCH_ALL
  3387.     SOM_ENDTRY
  3388.         
  3389.     return kODTrue;
  3390. }
  3391.  
  3392. //------------------------------------------------------------------------------
  3393. // CMDraft: NeedExternalizing
  3394. //------------------------------------------------------------------------------
  3395.  
  3396. SOM_Scope ODBoolean  SOMLINK CMDraftNeedExternalizing(CMDraft *somSelf, Environment *ev)
  3397. {
  3398.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3399.     CMDraftMethodDebug("CMDraft","NeedExternalizing");
  3400.  
  3401.     return _fExternalized;
  3402. }
  3403.  
  3404.  
  3405. //------------------------------------------------------------------------------
  3406. // CMDraft: GetIDList
  3407. //------------------------------------------------------------------------------
  3408.  
  3409. SOM_Scope IDList*  SOMLINK CMDraftGetIDList(CMDraft *somSelf, Environment *ev)
  3410. {
  3411.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3412.     CMDraftMethodDebug("CMDraft","GetIDList");
  3413.  
  3414.     return _fIDList;
  3415. }
  3416.  
  3417. //------------------------------------------------------------------------------
  3418. // CMDraft: IsChangedFromPrev
  3419. //------------------------------------------------------------------------------
  3420.  
  3421. SOM_Scope ODBoolean  SOMLINK CMDraftIsChangedFromPrev(CMDraft *somSelf, Environment *ev,
  3422.         VersionList* versionList)
  3423. {
  3424.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3425.     CMDraftMethodDebug("CMDraft","IsChangedFromPrev");
  3426.  
  3427.     ODBoolean        changedFromPrev = kODFalse;
  3428.     ODVersionID    prevVersionID;
  3429.     ODDraftID        prevDraftID;
  3430.     
  3431.     // If this draft has been modified, return kODTrue.
  3432.     
  3433.     if (_fChangedFromPrev != kODFalse)
  3434.         return kODTrue;
  3435.  
  3436.     // versionList->ChangedFromPrev is accurate only when the draft is
  3437.     // opened read-only. Therefore, additional check is needed to ensure that
  3438.     // we don't return kODTrue even when the draft has not be changed.
  3439.  
  3440.     SOM_TRY
  3441.         changedFromPrev = versionList->ChangedFromPrev(_fID);
  3442.         
  3443.         if ((changedFromPrev != kODFalse) && (_fPermissions == kODDPExclusiveWrite)) {
  3444.             prevDraftID = versionList->GetPreviousDraftID(_fID);
  3445.             prevVersionID = versionList->GetDraft(prevDraftID);
  3446.             if (prevVersionID == _fPrevVersionID)
  3447.                 changedFromPrev = kODFalse;
  3448.         }
  3449.     SOM_CATCH_ALL
  3450.     SOM_ENDTRY
  3451.     
  3452.     return changedFromPrev;
  3453. }
  3454.  
  3455. //------------------------------------------------------------------------------
  3456. // CMDraft: BeginClone
  3457. //------------------------------------------------------------------------------
  3458.  
  3459. SOM_Scope ODDraftKey  SOMLINK CMDraftBeginClone(CMDraft *somSelf, Environment *ev,
  3460.         ODDraft* destDraft,
  3461.         ODFrame* destFrame,
  3462.         ODCloneKind kind)
  3463. {
  3464.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3465.     CMDraftMethodDebug("CMDraft","BeginClone");
  3466.  
  3467.     OpenHashTable* clonedSUIDs = kODNULL;        ODVolatile(clonedSUIDs);
  3468.     OpenHashTable* weakClonedSUIDs = kODNULL;    ODVolatile(weakClonedSUIDs);
  3469.     OpenHashTable* linksToCloneSUIDs = kODNULL;    ODVolatile(linksToCloneSUIDs);
  3470.  
  3471.     ODDraftKey result = 0;
  3472.  
  3473.     SOM_TRY
  3474.  
  3475.         // Allow beginning a new clone into a link if a clone from a link
  3476.         // is in progress; common if the link contains promises
  3477.         if ( (kind == kODCloneToLink) && (_fCloneKind == kODCloneFromLink) )
  3478.         {
  3479.             if ( _fLockCount > 1 )
  3480.                 THROW(kODErrCloningInProgress);
  3481.         }
  3482.         else if (_fLockCount > 0)
  3483.             THROW(kODErrCloningInProgress);
  3484.  
  3485. #ifdef DebugClone
  3486.         somPrintf("\nCMDraft::BeginClone - ");
  3487.         switch (kind)
  3488.         {
  3489.         case kODCloneCut:        somPrintf("Cut\n"); break;
  3490.         case kODCloneCopy:        somPrintf("Copy\n"); break;
  3491.         case kODClonePaste:        somPrintf("Paste\n"); break;
  3492.         case kODCloneDropCopy:    somPrintf("Drop Copy\n"); break;
  3493.         case kODCloneDropMove:    somPrintf("Drop Move\n"); break;
  3494.         case kODCloneToLink:    somPrintf("To Link\n"); break;
  3495.         case kODCloneFromLink:    somPrintf("From Link\n"); break;
  3496.         case kODCloneAll:        somPrintf("All\n"); break;
  3497.         case kODCloneToFile:    somPrintf("To File\n"); break;
  3498.         default:                somPrintf("Invalid clone kind!\n"); break;
  3499.         }
  3500. #endif
  3501.  
  3502.         // Validate the clone kind parameter
  3503.         switch (kind)
  3504.         {
  3505.         case kODClonePaste:
  3506.         case kODCloneDropCopy:
  3507.         case kODCloneDropMove:
  3508.         case kODCloneToFile:
  3509.             {
  3510.             ODCloneKind origCloneKind = GetOriginalCloneKind(ev, somSelf);
  3511.             if ( (origCloneKind != kODCloneCut) && (origCloneKind != kODCloneCopy) )
  3512.                 THROW(kODErrInconsistentCloneKind);
  3513.             }
  3514.             if ( somSelf == destDraft )
  3515.                 THROW(kODErrInvalidDestinationDraft);
  3516.             break;
  3517.     
  3518.         case kODCloneCut:
  3519.         case kODCloneCopy:
  3520.             if ( somSelf == destDraft )
  3521.                 THROW(kODErrInvalidDestinationDraft);
  3522.             break;
  3523.     
  3524.         case kODCloneToLink:
  3525.         case kODCloneFromLink:
  3526.             if ( somSelf != destDraft )
  3527.                 THROW(kODErrInvalidDestinationDraft);
  3528.             break;
  3529.     
  3530.         case kODCloneAll:
  3531.             break;
  3532.     
  3533.         default:
  3534.             THROW(kODErrInvalidCloneKind);
  3535.             break;
  3536.         }
  3537.     
  3538.         ODMemoryHeapID heap = somSelf->GetHeap(ev);
  3539.  
  3540.         // Ensure both hash tables can be allocated
  3541.         if ( _fLockCount == 0 )
  3542.         {
  3543.             clonedSUIDs = new(heap) 
  3544.                 OpenHashTable(OpenHashTable::StdEqual,
  3545.                               OpenHashTable::StdHash, heap);
  3546.             clonedSUIDs->Initialize(kInitialHashTableEntries,
  3547.                                       sizeof(ODStorageUnitID),
  3548.                                       sizeof(ODStorageUnitID));
  3549.             
  3550.             if ( (kind == kODCloneCut) || (kind == kODCloneCopy) )
  3551.                 ReadClonedObjectTable(ev, clonedSUIDs, destDraft);
  3552.  
  3553.             if ( (kind == kODCloneDropCopy) ||
  3554.                  (kind == kODCloneDropMove) ||
  3555.                  (kind == kODClonePaste)    ||
  3556.                  (kind == kODCloneToFile) )
  3557.             {
  3558.                 if ( GetOriginalDraft(ev, somSelf) == kODNULL )
  3559.                 {
  3560.                     // Clone is from a document draft to a document draft,
  3561.                     // so create the table for deferred strong clones
  3562.                     linksToCloneSUIDs = new(heap) 
  3563.                         OpenHashTable(OpenHashTable::StdEqual,
  3564.                                       OpenHashTable::StdHash, heap);
  3565.                     linksToCloneSUIDs->Initialize(kInitialHashTableEntries,
  3566.                                               sizeof(ODStorageUnitID),
  3567.                                               sizeof(ODStorageUnitID));
  3568.                 }
  3569.             }
  3570.         }
  3571.  
  3572.         weakClonedSUIDs = new(heap) 
  3573.             OpenHashTable(OpenHashTable::StdEqual,
  3574.                           OpenHashTable::StdHash, heap);
  3575.         weakClonedSUIDs->Initialize(kInitialHashTableEntries,
  3576.                                       sizeof(ODStorageUnitID),
  3577.                                       sizeof(ODStorageUnitID));
  3578.  
  3579.         // BeginClone must not fail beyond this point
  3580.  
  3581.         _fLockCount++;
  3582.     
  3583.         if ( _fLockCount == 1 )
  3584.         {
  3585.             _fCurrentKey++;
  3586.             _fCloneKind = kind;
  3587.             _fDestDraft = destDraft;
  3588.             _fDestFrame = destFrame;
  3589.             
  3590.             _fAnyFrameCloned = kODFalse;
  3591.             _fRootPartReused = kODFalse;
  3592.         
  3593.             _fClonedSUIDs = clonedSUIDs;
  3594.             _fLinksToCloneSUIDs = linksToCloneSUIDs;
  3595.         }
  3596.     
  3597.         _fSavedWeakClonedSUIDs = _fWeakClonedSUIDs;
  3598.         _fWeakClonedSUIDs = weakClonedSUIDs;
  3599.         
  3600.         result = _fCurrentKey;
  3601.  
  3602.     SOM_CATCH_ALL
  3603.     
  3604.         ODDeleteObject(clonedSUIDs);
  3605.         ODDeleteObject(linksToCloneSUIDs);
  3606.         ODDeleteObject(weakClonedSUIDs);
  3607.  
  3608.     SOM_ENDTRY
  3609.     
  3610.     return result;
  3611. }
  3612.  
  3613. //------------------------------------------------------------------------------
  3614. // CMDraft: GetClonedSUIDs
  3615. //------------------------------------------------------------------------------
  3616.  
  3617. SOM_Scope OpenHashTable*  SOMLINK CMDraftGetClonedSUIDs(CMDraft *somSelf, Environment *ev,
  3618.         ODDraft* destDraft)
  3619. {
  3620.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3621.     CMDraftMethodDebug("CMDraft","GetClonedSUIDs");
  3622.  
  3623.     if ((_fDestDraft != kODNULL) && (_fDestDraft != destDraft)) {
  3624.         ODDeleteObject(_fClonedSUIDs);
  3625.         ODDeleteObject(_fWeakClonedSUIDs);
  3626.         ODSetSOMException(ev,kODErrInvalidDestinationDraft);
  3627.         return kODNULL;
  3628.     }
  3629.     _fDestDraft = destDraft;
  3630.     
  3631.     return _fClonedSUIDs;    
  3632. }
  3633.  
  3634. //------------------------------------------------------------------------------
  3635. // CMDraft: EndClone
  3636. //------------------------------------------------------------------------------
  3637.  
  3638. SOM_Scope void  SOMLINK CMDraftEndClone(CMDraft *somSelf, Environment *ev,
  3639.         ODDraftKey key)
  3640. {
  3641.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3642.     CMDraftMethodDebug("CMDraft","EndClone");
  3643.  
  3644.     ODStorageUnitID        fromID;
  3645.     ODStorageUnitID        toID;
  3646.  
  3647.     SOM_CATCH return;
  3648.  
  3649.     if ((key != _fCurrentKey) || (_fLockCount == 0))
  3650.         THROW(kODErrInvalidDraftKey);
  3651.  
  3652.     somSelf->DoDeferredClones(ev, key);
  3653.  
  3654.     OpenHashTableIterator iter(_fWeakClonedSUIDs);
  3655.     for (iter.First(&fromID, &toID); iter.IsNotComplete(); iter.Next(&fromID, &toID)) {
  3656.         if (toID != 0) {
  3657.             ODStorageUnit* toSU = _fDestDraft->AcquireStorageUnit(ev, toID);
  3658. #ifdef DebugClone
  3659.             somPrintf("Removing weakly cloned ID %d (%d)\n", toID, ((CMStorageUnit*) toSU)->GetObjectID(ev));
  3660. #endif
  3661.             _fDestDraft->RemoveStorageUnit(ev, toSU);
  3662.         }
  3663.     }
  3664.  
  3665.     switch (_fCloneKind)
  3666.     {
  3667.     case kODCloneCopy:
  3668.     case kODCloneCut:
  3669.         SetOriginalDraft(ev, _fDestDraft, somSelf);
  3670.         if ( !OriginalCloneKindExists(ev, _fDestDraft) )
  3671.             SetOriginalCloneKind(ev, _fDestDraft, _fCloneKind);
  3672.         WriteClonedObjectTable(ev, _fClonedSUIDs, _fDestDraft);
  3673.         break;
  3674.     
  3675.     case kODClonePaste:
  3676.     case kODCloneDropCopy:
  3677.     case kODCloneDropMove:
  3678.     case kODCloneToFile:
  3679.         if ( (_fCloneKind == kODClonePaste) && (GetOriginalCloneKind(ev, somSelf) == kODCloneCut) )
  3680.             SetOriginalCloneKind(ev, somSelf, kODCloneCopy);
  3681.         break;
  3682.  
  3683.     default:
  3684.         break;
  3685.     }
  3686.  
  3687.     if ( somSelf->GetCloneKind(ev) == kODCloneDropMove )
  3688.     {
  3689.         if ( GetOriginalDraft(ev, somSelf) == _fDestDraft )
  3690.         {
  3691.             if ( _fAnyFrameCloned )
  3692.             {
  3693.                 if ( somSelf->ContainingPartInClone(ev, _fDestFrame) )
  3694.                     THROW(kODErrMoveIntoSelf);
  3695.             }
  3696.         }
  3697.     }
  3698.  
  3699.     --_fLockCount;
  3700.     
  3701.     if ( _fLockCount == 0 )
  3702.     {
  3703.         _fDestDraft = kODNULL;
  3704.         _fDestFrame = kODNULL;
  3705.     
  3706.         ODDeleteObject(_fClonedSUIDs);
  3707.         ODDeleteObject(_fLinksToCloneSUIDs);
  3708.     }
  3709.  
  3710.     ODDeleteObject(_fWeakClonedSUIDs);
  3711.     _fWeakClonedSUIDs = _fSavedWeakClonedSUIDs;
  3712.  
  3713. #ifdef DebugClone
  3714.     somPrintf("CMDraft::EndClone - Clone completed\n\n");
  3715. #endif
  3716. }
  3717.  
  3718. //------------------------------------------------------------------------------
  3719. // CMDraft: AbortClone
  3720. //------------------------------------------------------------------------------
  3721.  
  3722. SOM_Scope void  SOMLINK CMDraftAbortClone(CMDraft *somSelf, Environment *ev,
  3723.         ODDraftKey key)
  3724. {
  3725.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3726.     CMDraftMethodDebug("CMDraft","AbortClone");
  3727.  
  3728.     SOM_CATCH return;
  3729.  
  3730. #if ODDebug_Drafts
  3731.     somPrintf("CMDraftAbort: %d\n", somSelf->GetID(ev));
  3732. #endif
  3733.  
  3734.     if ((key != _fCurrentKey) || (_fLockCount == 0))
  3735.         THROW(kODErrInvalidDraftKey);
  3736.  
  3737.     --_fLockCount;
  3738.  
  3739.     if ( _fLockCount == 0 )
  3740.     {
  3741.         _fDestDraft = kODNULL;
  3742.         _fDestFrame = kODNULL;
  3743.         
  3744.         ODDeleteObject(_fClonedSUIDs);
  3745.         ODDeleteObject(_fLinksToCloneSUIDs);
  3746.     }
  3747.  
  3748.     ODDeleteObject(_fWeakClonedSUIDs);
  3749.     _fWeakClonedSUIDs = _fSavedWeakClonedSUIDs;
  3750. }
  3751.  
  3752. //------------------------------------------------------------------------------
  3753. // CMDraft: SetOriginalID
  3754. //------------------------------------------------------------------------------
  3755.  
  3756. SOM_Scope void  SOMLINK CMDraftSetOriginalID(CMDraft *somSelf, Environment* ev,
  3757.         ODStorageUnitID destID,
  3758.         ODStorageUnitID originalID)
  3759. {
  3760.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3761.     CMDraftMethodDebug("CMDraft","SetOriginalID");
  3762.  
  3763.     SOM_CATCH return;
  3764.     
  3765.     TempODStorageUnit destSU = _fDestDraft->AcquireStorageUnit(ev, destID);
  3766.     ODSetULongProp(ev, destSU, kODPropOriginalID, kODULong, originalID);
  3767. }
  3768.  
  3769. //------------------------------------------------------------------------------
  3770. // CMDraft: GetOriginalID
  3771. //------------------------------------------------------------------------------
  3772. // An original ID may not be present in the root storage unit of the draft,
  3773. // since this SU is often constructed in place rather than cloned.
  3774. // An null object ID is returned if the property is not present.
  3775.  
  3776. SOM_Scope ODStorageUnitID  SOMLINK CMDraftGetOriginalID(CMDraft *somSelf, Environment* ev,
  3777.         ODStorageUnitID fromID)
  3778. {
  3779.     //CMDraftData *somThis = CMDraftGetData(somSelf);
  3780.     CMDraftMethodDebug("CMDraft","GetOriginalID");
  3781.     
  3782.     SOM_CATCH return 0;
  3783.  
  3784.     TempODStorageUnit fromSU = somSelf->AcquireStorageUnit(ev, fromID);
  3785.     return (ODStorageUnitID)ODGetULongProp(ev, fromSU, kODPropOriginalID, kODULong);
  3786. }
  3787.  
  3788. //------------------------------------------------------------------------------
  3789. // CheckPartAction
  3790. //------------------------------------------------------------------------------
  3791.  
  3792. static ODBoolean CheckPartAction(void* k, void* v, ODULong s, void* r)
  3793. {
  3794.     ODID            originalID =  * (ODID *) k;
  3795.     ODID            interupdateID = * (ODID *) v;
  3796.     OpenHashTable*    targetParts = (OpenHashTable*) r;
  3797.     ODBoolean        result = kODFalse;
  3798.     Environment*     ev = somGetGlobalEnvironment();
  3799.  
  3800.     // Note that storage units in the original document draft may not be up to date
  3801.     // if changes have not been externalized.  In particular, a frame's storage
  3802.     // unit may not have a valid reference to its part's storage unit.  For this
  3803.     // reason, use the storage units in the data interchange draft instead.
  3804.  
  3805. #ifdef DebugClone
  3806.     somPrintf("interupdateID %d, originalID %d\n", interupdateID, originalID);
  3807. #endif
  3808.  
  3809.     TempODStorageUnit interchangeSU = ::sInterchangeDraft->AcquireStorageUnit(ev, interupdateID);
  3810.     if ( ODSUExistsThenFocus(ev, interchangeSU, kODPropStorageUnitType, kODISOStr) )
  3811.     {
  3812.         if ( interchangeSU->GetSize(ev) == ODISOStrLength(kODFrameObject)+1 )
  3813.         {
  3814.             ODULong size = ODISOStrLength(kODFrameObject)+1;
  3815.             // Only read the same number of characters as in kODFrameObject, to prevent overwriting the
  3816.             // terminating zero byte of the buffer.
  3817.             if (ODGetISOStrProp(ev, interchangeSU, kODPropStorageUnitType, kODISOStr, (ODISOStr) ::sSUTypeBuffer, &size) 
  3818.                 != kODNULL)
  3819.             {
  3820.                 if (ODISOStrEqual(kODFrameObject, ::sSUTypeBuffer))
  3821.                 {
  3822.                     ODID interchangePartID = ODGetStrongSURefProp(ev, interchangeSU, kODPropPart, kODStrongStorageUnitRef);
  3823.                     if ( interchangePartID == kODNULLID )
  3824.                     {
  3825.                         // Note: If the reference isn't valid, ODGetStrongSURefProp will return
  3826.                         //   kODNULLID so it isn't necessary to call IsValidID instead.
  3827. #ifdef DebugClone
  3828.                         somPrintf("Invalid part reference from frame id %d\n", interupdateID);
  3829. #endif
  3830.                         result = kODTrue;    // Better safe than sorry!
  3831.                     }
  3832.                     else if ( interchangePartID != ::sRootPartIDToIgnore )
  3833.                     {
  3834.                         ODID targetPartID = ::sInterchangeDraft->GetOriginalID(ev, interchangePartID);
  3835. #ifdef DebugClone
  3836.                         somPrintf("Checking part id %d from frame id %d\n", targetPartID, originalID);
  3837. #endif
  3838.                         result = targetParts->Exists(&targetPartID);
  3839.                     }
  3840. #ifdef DebugClone
  3841.                     else
  3842.                     {
  3843.                         somPrintf("Skipping root part id %d because it was not cloned\n", interchangePartID);
  3844.                     }
  3845. #endif
  3846.                 }
  3847.             }
  3848.         }
  3849.     }
  3850.  
  3851.     return result;
  3852. }
  3853.  
  3854. //------------------------------------------------------------------------------
  3855. // CMDraft: ContainingPartInClone
  3856. //------------------------------------------------------------------------------
  3857.  
  3858. SOM_Scope ODBoolean  SOMLINK CMDraftContainingPartInClone(CMDraft *somSelf, Environment* ev,
  3859.         ODFrame* targetFrame)
  3860. {
  3861.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3862.     CMDraftMethodDebug("CMDraft","ContainingPartInClone");
  3863.  
  3864.     ODBoolean        result = kODFalse;
  3865.     ODFrame*        frame;
  3866.     ODFrame*        nextFrame;
  3867.     ODID            partID;
  3868.  
  3869.     OpenHashTable* targetParts = kODNULL;
  3870.     OpenHashTable* clonedSUIDs = kODNULL;
  3871.  
  3872.     SOM_TRY
  3873.  
  3874.         ODMemoryHeapID    heap = somSelf->GetHeap(ev);
  3875.  
  3876. #ifdef DebugClone
  3877.         somPrintf("ContainingPartInClone called with target frame id %d <%x>\n", targetFrame->GetID(ev), targetFrame);
  3878. #endif
  3879.  
  3880.         OpenHashTable* targetParts = new(heap) OpenHashTable(OpenHashTable::StdEqual,
  3881.                                                               OpenHashTable::StdHash,
  3882.                                                               heap);
  3883.         targetParts->Initialize(kInitialHashTableEntries, sizeof(ODID), 0, kODTrue);
  3884.     
  3885.         // Build a table of parts that own or embed the target frame
  3886.         frame = targetFrame;
  3887.         if ( frame )
  3888.             frame->Acquire(ev);
  3889.         while ( frame != kODNULL )
  3890.         {
  3891.             TempODFrame tempFrame = frame; // ensure it's released
  3892.             ODPart* part = frame->AcquirePart(ev);
  3893.             partID = part->GetID(ev);
  3894.             part->Release(ev);
  3895. #ifdef DebugClone
  3896.             somPrintf("Adding target part id %d from frame id %d\n", partID, frame->GetID(ev));
  3897. #endif
  3898.             targetParts->ReplaceEntry(&partID, kODNULL);
  3899.     
  3900.             nextFrame = frame->AcquireContainingFrame(ev);
  3901.             if ( nextFrame == kODNULL )
  3902.             {
  3903.                 { TempODWindow window = frame->AcquireWindow(ev);
  3904.                   nextFrame = window->AcquireSourceFrame(ev);
  3905.                 }
  3906.  
  3907.                 // The source frame always displays the same part, so skip to its containing frame.
  3908.                 // Note that it must have a containing frame.
  3909.                 if ( nextFrame != kODNULL )
  3910.                 {
  3911.                     TempODFrame sourceFrame = nextFrame;
  3912.                     nextFrame = sourceFrame->AcquireContainingFrame(ev);
  3913.                 }
  3914.             }
  3915.             frame = nextFrame;
  3916.         }
  3917.     
  3918.         clonedSUIDs = new(heap) OpenHashTable(OpenHashTable::StdEqual,
  3919.                                                  OpenHashTable::StdHash,
  3920.                                                  heap);
  3921.  
  3922.         clonedSUIDs->Initialize(kInitialHashTableEntries,
  3923.                                   sizeof(ODStorageUnitID),
  3924.                                   sizeof(ODStorageUnitID));
  3925.     
  3926.         // Get the table of objects cloned into the data interchange draft
  3927.         ReadClonedObjectTable(ev, clonedSUIDs, somSelf);
  3928.                 
  3929.         // See if any frame of any target part is part of the clone
  3930.         ::sInterchangeDraft = somSelf;
  3931.         ::sSUTypeBuffer = (ODISOStr) ODNewPtrClear(ODISOStrLength(kODFrameObject) + 1);
  3932.         ::sRootPartIDToIgnore = ( _fRootPartReused ? kODNULLID : RootPartID(ev, somSelf) );
  3933.         result = clonedSUIDs->Walk(CheckPartAction, targetParts);
  3934.         ODDisposePtr(::sSUTypeBuffer);
  3935.     
  3936.     SOM_CATCH_ALL
  3937.     
  3938.     SOM_ENDTRY
  3939.  
  3940.     ODDeleteObject(targetParts);
  3941.     ODDeleteObject(clonedSUIDs);
  3942.     
  3943. #ifdef DebugClone
  3944.     somPrintf("ContainingPartInClone returns %d\n", result);
  3945. #endif
  3946.  
  3947.     return result;
  3948. }
  3949.  
  3950. //------------------------------------------------------------------------------
  3951. // CompanionObjectID
  3952. //------------------------------------------------------------------------------
  3953.  
  3954. SOM_Scope ODID  SOMLINK CMDraftCompanionObjectID(CMDraft *somSelf, Environment *ev,
  3955.     ODID objectID)
  3956. {
  3957.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3958.     CMDraftMethodDebug("CMDraft","CompanionObjectID");
  3959.  
  3960.     ODStorageUnitID companionID = kODNULLID;
  3961.     ODPropertyName companionProperty = kODNULL;
  3962.  
  3963.     SOM_TRY
  3964.  
  3965.         if ( IsLinkObject(ev, somSelf, objectID) )
  3966.             companionProperty = kODPropLinkSource;
  3967.         else if ( IsLinkSourceObject(ev, somSelf, objectID) )
  3968.             companionProperty = kODPropLink;
  3969.     
  3970.         if ( companionProperty != kODNULL )
  3971.         {
  3972.             TempODStorageUnit objectSU = somSelf->AcquireStorageUnit(ev, objectID);
  3973.             if ( objectSU != kODNULL )
  3974.             {
  3975.                 companionID = ODGetWeakSURefProp(ev, objectSU, companionProperty, kODWeakStorageUnitRef);
  3976.             }
  3977.         }
  3978.  
  3979.     SOM_CATCH_ALL
  3980.  
  3981.     SOM_ENDTRY
  3982.  
  3983.     return companionID;
  3984. }
  3985.  
  3986. //------------------------------------------------------------------------------
  3987. //  CMDraft: CloneCompanionObject
  3988. //------------------------------------------------------------------------------
  3989. // If fromID is a link or link source object, clone its companion.
  3990. // Note that kODNULLID is always used as the scopeID, since scope is irrelevant
  3991. // for link and link source objects.
  3992.  
  3993. SOM_Scope ODID  SOMLINK CMDraftCloneCompanionObject(CMDraft *somSelf, Environment *ev,
  3994.         ODDraftKey key,
  3995.         ODID fromID)
  3996. {
  3997.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3998.     CMDraftMethodDebug("CMDraft","CloneCompanionObject");
  3999.  
  4000.     ODID toID = kODNULLID;    ODVolatile(toID);
  4001.  
  4002.     SOM_TRY
  4003.  
  4004.         ODStorageUnitID companionID = somSelf->CompanionObjectID(ev, fromID);
  4005.         if ( companionID != kODNULLID )
  4006.         {
  4007.             // Optimization: If the companion object has already been cloned,
  4008.             // there is no need to clone it again since scope is irrelevant for
  4009.             // these objects. [cc 9/28/95]
  4010.             _fClonedSUIDs->GetValue(&companionID, &toID);
  4011.             if ( toID == kODNULLID ) 
  4012.                 toID = somSelf->StrongClone(ev, key, companionID, kODNULLID, kODNULLID);
  4013.         }
  4014.  
  4015.     SOM_CATCH_ALL
  4016.     
  4017.     SOM_ENDTRY
  4018.  
  4019.     return toID;
  4020. }
  4021.  
  4022. //------------------------------------------------------------------------------
  4023. //  CMDraft: CompanionWasCloned
  4024. //------------------------------------------------------------------------------
  4025.  
  4026. SOM_Scope ODBoolean  SOMLINK CMDraftCompanionWasCloned(CMDraft *somSelf, Environment* ev,
  4027.         ODStorageUnitID fromID)
  4028. {
  4029.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4030.     CMDraftMethodDebug("CMDraft","CompanionWasCloned");
  4031.  
  4032.     ODBoolean result = kODFalse;
  4033.     
  4034.     SOM_TRY
  4035.         result = (somSelf->CompanionObjectID(ev, fromID) != kODNULLID);
  4036.     SOM_CATCH_ALL
  4037.     SOM_ENDTRY
  4038.  
  4039.     return result;
  4040. }
  4041.  
  4042. //------------------------------------------------------------------------------
  4043. //  CMDraft: GetCloneKind
  4044. //------------------------------------------------------------------------------
  4045.  
  4046. SOM_Scope ODCloneKind  SOMLINK CMDraftGetCloneKind(CMDraft *somSelf, Environment* ev)
  4047. {
  4048.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4049.     CMDraftMethodDebug("CMDraft","GetCloneKind");
  4050.     
  4051.     ODCloneKind cloneKind = _fCloneKind;
  4052.  
  4053.     SOM_TRY
  4054.  
  4055.     if ( cloneKind == kODClonePaste )
  4056.     {
  4057.         if ( (GetOriginalCloneKind(ev, somSelf) == kODCloneCut) && (GetOriginalDraft(ev, somSelf) == _fDestDraft) )
  4058.             cloneKind = kODCloneDropMove;
  4059.         else
  4060.             cloneKind = kODCloneDropCopy;
  4061.     }
  4062.     else if ( cloneKind == kODCloneToFile )
  4063.     {
  4064.         cloneKind = kODCloneDropCopy;
  4065.     }
  4066.     
  4067.     SOM_CATCH_ALL
  4068.     SOM_ENDTRY
  4069.     return cloneKind;
  4070. }
  4071.  
  4072. //------------------------------------------------------------------------------
  4073. //  CMDraft: DeferStrongClone
  4074. //------------------------------------------------------------------------------
  4075. //
  4076. // Defers cloning of a link or link source object in this draft to the 
  4077. // destination draft.  As in a weak clone, a storage unit is created in the
  4078. // destination draft an its ID is returned.  In addition, the object is put
  4079. // in a list of link objects.  EndClone should iterate over the list and
  4080. // clone those objects once the fate of their companion objects is known.
  4081.  
  4082. SOM_Scope ODID  SOMLINK CMDraftDeferStrongClone(CMDraft *somSelf, Environment* ev,
  4083.         ODID fromID)
  4084. {
  4085.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4086.     CMDraftMethodDebug("CMDraft","DeferStrongClone");
  4087.  
  4088.     ODID toID = kODNULLID; ODVolatile(toID);
  4089.  
  4090.     SOM_TRY
  4091.  
  4092.         ASSERT(IsEitherLinkObject(ev, somSelf, fromID), kODErrInvalidID);
  4093.  
  4094.         ASSERT(_fLinksToCloneSUIDs != kODNULL, kODErrCannotDeferClone);
  4095.  
  4096.         _fWeakClonedSUIDs->GetValue(&fromID, &toID);
  4097.         if ( toID == kODNULLID )
  4098.         {
  4099.             TempODStorageUnit toSU = _fDestDraft->CreateStorageUnit(ev);
  4100.             toID = toSU->GetID(ev);
  4101.             _fWeakClonedSUIDs->ReplaceEntry(&fromID, &toID);
  4102. #ifdef DebugClone
  4103.             somPrintf("Putting deferred clone from ID %d to ID %d on weak clone list\n", fromID, toID);
  4104. #endif
  4105.         }
  4106.  
  4107.         ODID toCloneID = kODNULLID;
  4108.         _fLinksToCloneSUIDs->GetValue(&fromID, &toCloneID);
  4109.         if ( toCloneID == kODNULLID )
  4110.         {
  4111.             _fLinksToCloneSUIDs->ReplaceEntry(&fromID, &toID);
  4112. #ifdef DebugClone
  4113.             somPrintf("Deferring clone from ID %d to ID %d\n", fromID, toID);
  4114. #endif
  4115.         }
  4116.  
  4117.     SOM_CATCH_ALL
  4118.  
  4119.     SOM_ENDTRY
  4120.  
  4121.     return toID;
  4122. }
  4123.  
  4124. //------------------------------------------------------------------------------
  4125. //  CMDraft: DoDeferredClones
  4126. //------------------------------------------------------------------------------
  4127.  
  4128. SOM_Scope void  SOMLINK CMDraftDoDeferredClones(CMDraft *somSelf, Environment* ev,
  4129.     ODDraftKey    key)
  4130. {
  4131.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4132.     CMDraftMethodDebug("CMDraft","DoDeferredClones");
  4133.  
  4134.     ODStorageUnitID fromID;
  4135.     ODStorageUnitID toID;
  4136.     ODStorageUnitID companionID;
  4137.     ODStorageUnitID toCompanionID;
  4138.  
  4139.     if ( _fLinksToCloneSUIDs != kODNULL )
  4140.     {
  4141.         SOM_TRY
  4142.  
  4143. #ifdef DebugClone
  4144.             somPrintf("Cloning deferred link and link source objects\n");
  4145. #endif
  4146.  
  4147.             OpenHashTableIterator iter(_fLinksToCloneSUIDs);
  4148.             for (iter.First(&fromID, &toID); iter.IsNotComplete(); iter.Next(&fromID, &toID))
  4149.             {
  4150.                 companionID = somSelf->CompanionObjectID(ev, fromID);
  4151.                 if ( companionID != kODNULLID )
  4152.                 {
  4153.                     // Because cloning both link and link source objects is deferred,
  4154.                     // it suffices to check just _fLinksToCloneSUIDs to see if the
  4155.                     // companion has also been deferred.
  4156.                     toCompanionID = kODNULLID;    // GetValue doesn't change if not found
  4157.                     _fLinksToCloneSUIDs->GetValue(&companionID, &toCompanionID);
  4158.                     if ( toCompanionID != kODNULLID )
  4159.                     {
  4160.                         // Previously, we just created a storage unit for the object,
  4161.                         // so now we must clone into that storage unit
  4162.                         somSelf->StrongClone(ev, key, fromID, toID, kODNULLID);
  4163.                     }
  4164.                     else
  4165.                     {
  4166.                         // The empty storage unit created in the destination draft
  4167.                         // will be removed with others that were only weakly cloned
  4168. #ifdef DebugClone
  4169.                         somPrintf("Companion object ID %d of ID %d was not cloned\n", companionID, fromID);
  4170. #endif
  4171.                     }
  4172.                 }
  4173.                 else
  4174.                 {
  4175. #ifdef DebugClone
  4176.                     somPrintf("No companion for object ID %d\n", fromID);
  4177. #endif
  4178.                 }
  4179.             }
  4180.  
  4181.         SOM_CATCH_ALL
  4182.         
  4183.         SOM_ENDTRY
  4184.     }
  4185. }
  4186.  
  4187. //------------------------------------------------------------------------------
  4188. //  CMDraft: DropCopyClone
  4189. //------------------------------------------------------------------------------
  4190. //
  4191. // Implements strong cloning of objects during a paste or drop of copied content.
  4192. // Takes into consideration whether the source draft is an
  4193. // intermediate draft or a document draft (for example, an OpenDoc file dragged
  4194. // in from the Finder).  If the clone is from an intermediat draft back into
  4195. // the same document draft, the original object ID may be substituted, or a null
  4196. // object ID may be returned.  Enforces rules for copying link source and link
  4197. // objects.
  4198.  
  4199. SOM_Scope ODID  SOMLINK CMDraftDropCopyClone(CMDraft *somSelf, Environment* ev,
  4200.         ODDraftKey    key,
  4201.         ODID        fromID,
  4202.         ODID        toID,
  4203.         ODID        scopeID)
  4204. {
  4205.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4206.     CMDraftMethodDebug("CMDraft","DropCopyClone");
  4207.  
  4208.     ODID clonedID = kODNULLID; ODVolatile(clonedID);
  4209.  
  4210.     SOM_TRY
  4211.  
  4212.         ASSERT(somSelf->GetCloneKind(ev) == kODCloneDropCopy, kODErrInvalidCloneKind);
  4213.     
  4214.         if ( IsLinkObject(ev, somSelf, fromID) )
  4215.         {
  4216.             ODDraft* originalDraft = GetOriginalDraft(ev, somSelf);
  4217.             if ( originalDraft == _fDestDraft )
  4218.             {
  4219.                 // Clone is from an intermediate draft back into the original draft.
  4220.                 // Because the clone is from an intermediate draft, we can check
  4221.                 // to see if the link source object was also cloned into the
  4222.                 // intermediate draft.
  4223.                 if ( somSelf->CompanionWasCloned(ev, fromID) )
  4224.                 {
  4225.                     // The link source object was copied, so clone the link object
  4226.                     // to create a new one.
  4227.                     clonedID = somSelf->StrongClone(ev, key, fromID, toID, scopeID);
  4228.                 }
  4229.                 else
  4230.                 {
  4231.                     // The link source object was not cloned, so substitute the ID
  4232.                     // of the original link object so copied destinations reference
  4233.                     // the original link object.
  4234.                     ASSERT(toID == 0, kODErrInvalidID);
  4235.                     clonedID = somSelf->GetOriginalID(ev, fromID);
  4236.                     ASSERT(_fDestDraft->IsValidID(ev, clonedID), kODErrInvalidID);
  4237. #ifdef DebugClone
  4238.                     somPrintf("Reusing existing link object id = %d for cloned object %d\n", clonedID, fromID);
  4239. #endif
  4240.                 }
  4241.             }
  4242.             else if ( originalDraft != kODNULL )
  4243.             {
  4244.                 // Clone is cross-draft via an intermediate draft.  Only link
  4245.                 // and link source pairs are copied.
  4246.                 // Because the clone is from an intermediate draft, we can check
  4247.                 // to see if the link source object was also cloned into the
  4248.                 // intermediate draft.
  4249.                 if ( somSelf->CompanionWasCloned(ev, fromID) )
  4250.                 {
  4251.                     // The link source object was copied, so clone the link object
  4252.                     // to create a new one.
  4253.                     clonedID = somSelf->StrongClone(ev, key, fromID, toID, scopeID);
  4254.                 }
  4255.                 else
  4256.                 {
  4257.                     // The link source object was not cloned, so don't clone the link
  4258.                     clonedID = kODNULLID;
  4259. #ifdef DebugClone
  4260.                     somPrintf("CMDraftStrongClone NOT cloning from ID %d\n", fromID);
  4261. #endif
  4262.                 }
  4263.             }
  4264.             else
  4265.             {
  4266.                 // Clone is from a document draft.  Create a storage unit and return
  4267.                 // its ID.  EndClone will either clone the object or remove the
  4268.                 // storage unit from the destination draft.
  4269.                 clonedID = somSelf->DeferStrongClone(ev, fromID);
  4270.             }
  4271.         }
  4272.         else if ( IsLinkSourceObject(ev, somSelf, fromID) )
  4273.         {
  4274.             if ( GetOriginalDraft(ev, somSelf) != kODNULL )
  4275.             {
  4276.                 // Clone is from an intermediate draft (it doesn't matter if the
  4277.                 // destination draft is the same as the original draft or not).
  4278.                 // Because the clone is from an intermediate draft, we can check
  4279.                 // to see if the link object was also cloned into the
  4280.                 // intermediate draft.
  4281.                 if ( somSelf->CompanionWasCloned(ev, fromID) )
  4282.                 {
  4283.                     // The link object was copied, so clone the link source object
  4284.                     // to create a new one.
  4285.                     clonedID = somSelf->StrongClone(ev, key, fromID, toID, scopeID);
  4286.                 }
  4287.                 else
  4288.                 {
  4289.                     // The link object was not cloned, so don't clone the link source
  4290.                     clonedID = kODNULLID;
  4291. #ifdef DebugClone
  4292.                     somPrintf("CMDraftStrongClone NOT cloning from ID %d\n", fromID);
  4293. #endif
  4294.                 }
  4295.             }
  4296.             else
  4297.             {
  4298.                 // Clone is from a document draft.  Create a storage unit and return
  4299.                 // its ID.  EndClone will either clone the object or remove the
  4300.                 // storage unit from the destination draft.
  4301.                 clonedID = somSelf->DeferStrongClone(ev, fromID);
  4302.             }
  4303.         }
  4304.         else
  4305.         {
  4306.             // Not a link or link source object, so clone it
  4307.             clonedID = somSelf->StrongClone(ev, key, fromID, toID, scopeID);
  4308.         }
  4309.     
  4310.     SOM_CATCH_ALL
  4311.     
  4312.     SOM_ENDTRY
  4313.  
  4314.     return clonedID;
  4315. }
  4316.  
  4317. //------------------------------------------------------------------------------
  4318. //  CMDraft: DropMoveClone
  4319. //------------------------------------------------------------------------------
  4320. //
  4321. // Implements strong cloning of objects during a paste of cut content or a drop
  4322. // of moved content.  Takes into consideration wether the source draft is an
  4323. // intermediate draft or a document draft (for example, an OpenDoc file dragged
  4324. // in from the Finder).  If the clone is from an intermediate draft back into
  4325. // the same document draft, the original object ID may be substituted, or a null
  4326. // object ID may be returned.  Enforces rules for moving link source and link
  4327. // objects. When moved to another draft, links behave as if copied.
  4328.  
  4329. SOM_Scope ODID  SOMLINK CMDraftDropMoveClone(CMDraft *somSelf, Environment* ev,
  4330.         ODDraftKey    key,
  4331.         ODID        fromID,
  4332.         ODID        toID,
  4333.         ODID        scopeID)
  4334. {
  4335.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4336.     CMDraftMethodDebug("CMDraft","DropMoveClone");
  4337.  
  4338.     ODID clonedID = kODNULLID; ODVolatile(clonedID);
  4339.  
  4340.     SOM_TRY
  4341.  
  4342.         ASSERT(somSelf->GetCloneKind(ev) == kODCloneDropMove, kODErrInvalidCloneKind);
  4343.     
  4344.         ODDraft* originalDraft = GetOriginalDraft(ev, somSelf);
  4345.         if ( originalDraft == _fDestDraft )
  4346.         {
  4347.             // Clone is from an intermediate draft back into the original draft.
  4348.             // In this case, no distinction is made between link, link source,
  4349.             // and other objects being cloned.
  4350.             // toID will be non-zero if the object has already been weakly cloned.
  4351.             // If the original object is still present in the destination draft,
  4352.             // use it unless the caller explicitly cloned into another storage unit.
  4353.             ODID originalID = somSelf->GetOriginalID(ev, fromID);
  4354.             if ( _fDestDraft->IsValidID(ev, originalID) )
  4355.             {
  4356.                 if ( (toID == 0) || (toID == originalID) )
  4357.                 {
  4358.                     clonedID = originalID;
  4359. #ifdef DebugClone
  4360.                     somPrintf("CMDraftStrongClone from ID %d to substitute ID %d\n", fromID, clonedID);
  4361. #endif
  4362.                 }
  4363.                 else
  4364.                     clonedID = somSelf->StrongClone(ev, key, fromID, toID, scopeID);
  4365.             }
  4366.             else
  4367.             {
  4368.                 clonedID = somSelf->StrongClone(ev, key, fromID, toID, scopeID);
  4369. #ifdef DebugClone
  4370.                 if ( originalID != kODNULLID )
  4371.                     somPrintf("Original id = %d is not valid\n", originalID);
  4372. #endif
  4373.             }
  4374.             somSelf->CheckClonedObject(ev, fromID, clonedID, originalID);
  4375.         }
  4376.         else if ( IsEitherLinkObject(ev, somSelf, fromID) )
  4377.         {
  4378.             if ( originalDraft != kODNULL )
  4379.             {
  4380.                 // Clone is cross-draft via an intermediate draft.  Only link
  4381.                 // and link source pairs are copied.
  4382.                 // Because the clone is from an intermediate draft, we can check
  4383.                 // to see if the companion object was also cloned into the
  4384.                 // intermediate draft.
  4385.                 if ( somSelf->CompanionWasCloned(ev, fromID) )
  4386.                 {
  4387.                     // The link source object was copied, so clone the link object
  4388.                     // to create a new one.
  4389.                     clonedID = somSelf->StrongClone(ev, key, fromID, toID, scopeID);
  4390.                 }
  4391.                 else
  4392.                 {
  4393.                     // The companion object was not cloned, so don't clone the link
  4394.                     clonedID = kODNULLID;
  4395. #ifdef DebugClone
  4396.                     somPrintf("CMDraftStrongClone NOT cloning from ID %d\n", fromID);
  4397. #endif
  4398.                 }
  4399.             }
  4400.             else
  4401.             {
  4402.                 // Clone is from a document draft.  Create a storage unit and return
  4403.                 // its ID.  EndClone will either clone the object or remove the
  4404.                 // storage unit from the destination draft.
  4405.                 clonedID = somSelf->DeferStrongClone(ev, fromID);
  4406.             }
  4407.         }
  4408.         else
  4409.         {
  4410.             // Other objects moved across drafts are always cloned
  4411.             clonedID = somSelf->StrongClone(ev, key, fromID, toID, scopeID);
  4412.         }
  4413.     
  4414.     SOM_CATCH_ALL
  4415.     
  4416.     SOM_ENDTRY
  4417.  
  4418.     return clonedID;
  4419. }
  4420.  
  4421. //------------------------------------------------------------------------------
  4422. //  CMDraft: DoWeakClone
  4423. //------------------------------------------------------------------------------
  4424. //
  4425. // Implements weak clone of objects that have not already been strongly or
  4426. // weakly cloned.
  4427. // If link objects are copied or moved across a draft...
  4428.  
  4429. SOM_Scope ODID  SOMLINK CMDraftDoWeakClone(CMDraft *somSelf, Environment* ev,
  4430.         ODID fromID)
  4431. {
  4432.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4433.     CMDraftMethodDebug("CMDraft","DoWeakClone");
  4434.  
  4435.     ODID        clonedID = kODNULLID; ODVolatile(clonedID);
  4436.     ODBoolean    doWeakClone = kODFalse;
  4437.     ODDraft*    originalDraft = kODNULL;
  4438.  
  4439.     SOM_TRY
  4440.  
  4441.         ODCloneKind cloneKind = somSelf->GetCloneKind(ev);
  4442.         
  4443.         if ( cloneKind == kODCloneDropCopy )
  4444.         {
  4445.             if ( IsLinkObject(ev, somSelf, fromID) )
  4446.             {
  4447.                 originalDraft = GetOriginalDraft(ev, somSelf);
  4448.                 if ( originalDraft == _fDestDraft )
  4449.                 {
  4450.                     // Clone is from an intermediate draft back into the original draft.
  4451.                     // Because the clone is from an intermediate draft, we can check
  4452.                     // to see if the link source object was also cloned into the
  4453.                     // intermediate draft.
  4454.                     if ( somSelf->CompanionWasCloned(ev, fromID) )
  4455.                     {
  4456.                         // The link source object was copied, so clone the link object
  4457.                         // to create a new one.
  4458.                         doWeakClone = kODTrue;
  4459.                     }
  4460.                     else
  4461.                     {
  4462.                         // The link source object was not cloned, so substitute the ID
  4463.                         // of the original link object so copied destinations reference
  4464.                         // the original link object.
  4465.                         clonedID = somSelf->GetOriginalID(ev, fromID);
  4466.                         ASSERT(_fDestDraft->IsValidID(ev, clonedID), kODErrInvalidID);
  4467. #ifdef DebugClone
  4468.                         somPrintf("Reusing existing link object id = %d for weakly cloned object %d\n", clonedID, fromID);
  4469. #endif
  4470.                     }
  4471.                 }
  4472.                 else if ( originalDraft != kODNULL )
  4473.                 {
  4474.                     // Clone is cross-draft via an intermediate draft.  Only link
  4475.                     // and link source pairs are copied.
  4476.                     // Because the clone is from an intermediate draft, we can check
  4477.                     // to see if the link source object was also cloned into the
  4478.                     // intermediate draft.  If the link source was cloned, we can
  4479.                     // weakly clone this link object.
  4480.  
  4481.                     doWeakClone = somSelf->CompanionWasCloned(ev, fromID);
  4482.                 }
  4483.                 else
  4484.                 {
  4485.                     // Clone is from a document draft.  Weakly clone it.
  4486.                     doWeakClone = kODTrue;
  4487.                 }
  4488.             }
  4489.             else if ( IsLinkSourceObject(ev, somSelf, fromID) )
  4490.             {
  4491.                 originalDraft = GetOriginalDraft(ev, somSelf);
  4492.                 if ( originalDraft != kODNULL )
  4493.                 {
  4494.                     // Clone is from an intermediate draft.
  4495.                     // Because the clone is from an intermediate draft, we can check
  4496.                     // to see if the link object was also cloned into the
  4497.                     // intermediate draft.
  4498.                     doWeakClone = somSelf->CompanionWasCloned(ev, fromID);
  4499.                 }
  4500.                 else
  4501.                 {
  4502.                     // Clone is from a document draft.  Weakly clone it.
  4503.                     doWeakClone = kODTrue;
  4504.                 }
  4505.             }
  4506.             else
  4507.             {
  4508.                 // Weakly clone all other objects
  4509.                 doWeakClone = kODTrue;
  4510.             }
  4511.         }
  4512.         else if ( cloneKind == kODCloneDropMove )
  4513.         {
  4514.             originalDraft = GetOriginalDraft(ev, somSelf);
  4515.             if ( originalDraft == _fDestDraft )
  4516.             {
  4517.                 // Clone is from an intermediate draft back into the original draft.
  4518.                 // In this case, no distinction is made between link, link source,
  4519.                 // and other objects being cloned.
  4520.                 ODID originalID = somSelf->GetOriginalID(ev, fromID);
  4521.                 if ( _fDestDraft->IsValidID(ev, originalID) )
  4522.                 {
  4523.                     clonedID = originalID;
  4524.                     
  4525.                     // Assumption: If the original object is substituted for a
  4526.                     // weakly-referenced clone, the clone is also strongly-referenced
  4527.                     // and will be strongly cloned back into the draft, so its
  4528.                     // unnecessary to call somSelf->CheckClonedObject here.
  4529.                 }
  4530.                 else
  4531.                 {
  4532.                     doWeakClone = kODTrue;
  4533. #ifdef DebugClone
  4534.                     if ( originalID != kODNULLID )
  4535.                         somPrintf("Original id = %d is not valid\n", originalID);
  4536. #endif
  4537.                 }
  4538.             }
  4539.             else if ( IsEitherLinkObject(ev, somSelf, fromID) )
  4540.             {
  4541.                 if ( originalDraft != kODNULL )
  4542.                 {
  4543.                     // Clone is cross-draft via an intermediate draft.  Only link
  4544.                     // and link source pairs are copied.
  4545.                     // Because the clone is from an intermediate draft, we can check
  4546.                     // to see if the link source object was also cloned into the
  4547.                     // intermediate draft.
  4548.                     doWeakClone = somSelf->CompanionWasCloned(ev, fromID);
  4549.                 }
  4550.                 else
  4551.                 {
  4552.                     // Clone is from a document draft.
  4553.                     doWeakClone = kODTrue;
  4554.                 }
  4555.             }
  4556.             else
  4557.             {
  4558.                 // Other objects moved across drafts are always cloned
  4559.                 doWeakClone = kODTrue;
  4560.             }
  4561.         }
  4562.         else
  4563.         {
  4564.             // Note a paste or a drop; do a weak clone
  4565.             doWeakClone = kODTrue;
  4566.         }
  4567.  
  4568.         if ( doWeakClone )
  4569.         {
  4570.             TempODStorageUnit toSU = _fDestDraft->CreateStorageUnit(ev);
  4571.             clonedID = toSU->GetID(ev);
  4572.             _fWeakClonedSUIDs->ReplaceEntry(&fromID, &clonedID);
  4573.         }
  4574.  
  4575. #ifdef DebugClone
  4576.         if ( doWeakClone )
  4577.             somPrintf("CMDraftWeakClone from ID %d to ID %d", fromID, clonedID);
  4578.         else
  4579.             somPrintf("CMDraftWeakClone from ID %d to substitute ID %d", fromID, clonedID);
  4580.         TempODISOStr suType = GetStorageUnitType(ev, somSelf, fromID);
  4581.         somPrintf(" type %s\n", (ODISOStr) suType);
  4582. #endif
  4583.  
  4584.     SOM_CATCH_ALL
  4585.     
  4586.     SOM_ENDTRY
  4587.  
  4588.     return clonedID;
  4589. }
  4590.  
  4591. //------------------------------------------------------------------------------
  4592. // CMDraft: Clone
  4593. //------------------------------------------------------------------------------
  4594. //
  4595. // It should really be replaced by a table-driven algorithm.  There are only 
  4596. // three possible actions when cloning a link or link source object:
  4597. //        (1) Go ahead and clone the link,
  4598. //        (2) Don't clone the link,
  4599. //        (3) Substitute the original link rather than clone in a duplicate
  4600. // However, there are four factors that determine which action should be taken.
  4601. // There are 8x3x2x2 = 96 distinct combinations of these factors; however,
  4602. // most combinations are impossible or illegal.
  4603. // The switch statement is an embodyment in code of the resulting sparse matrix.
  4604. // Several cases are sometimes handled at once.  Only by going back to the full 
  4605. // case analysis represented by a table can one understand this code.
  4606. // 
  4607. // Note that its possible that a link object's companion doesn't exist; in this
  4608. // case the link is broken and won't be copied.
  4609. // 
  4610.  
  4611. SOM_Scope ODID  SOMLINK CMDraftClone(CMDraft *somSelf, Environment *ev,
  4612.         ODDraftKey key,
  4613.         ODID fromID,
  4614.         ODID toObjectID,
  4615.         ODID scopeID)
  4616. {
  4617.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4618.     CMDraftMethodDebug("CMDraft","Clone");
  4619.  
  4620.     SOM_CATCH return 0;
  4621.  
  4622.     if ((key != _fCurrentKey) || (_fLockCount == 0))
  4623.         THROW(kODErrInvalidDraftKey);
  4624.  
  4625.     ODStorageUnitID    toID = 0;
  4626.  
  4627.     switch ( somSelf->GetCloneKind(ev) )
  4628.     {
  4629.     case kODCloneAll:
  4630.         toID = somSelf->StrongClone(ev, key, fromID, toObjectID, scopeID);
  4631.         somSelf->CloneCompanionObject(ev, key, fromID);
  4632.         break;
  4633.  
  4634.     case kODCloneFromLink:
  4635.     case kODCloneToLink:
  4636.         if ( IsNeitherLinkObject(ev, somSelf, fromID) )
  4637.             toID = somSelf->StrongClone(ev, key, fromID, toObjectID, scopeID);
  4638.         break;
  4639.  
  4640.     case kODCloneCopy:
  4641.     case kODCloneCut:
  4642.         toID = somSelf->StrongClone(ev, key, fromID, toObjectID, scopeID);
  4643.         somSelf->SetOriginalID(ev, toID, fromID);
  4644.         break;
  4645.         
  4646.     case kODCloneDropCopy:
  4647.         toID = somSelf->DropCopyClone(ev, key, fromID, toObjectID, scopeID);
  4648.         break;
  4649.  
  4650.     case kODCloneDropMove:
  4651.         toID = somSelf->DropMoveClone(ev, key, fromID, toObjectID, scopeID);
  4652.         break;
  4653.  
  4654.     default:
  4655.         break;
  4656.     }
  4657.  
  4658.     return toID;
  4659. }
  4660.  
  4661. //------------------------------------------------------------------------------
  4662. // CMDraft: StrongClone
  4663. //------------------------------------------------------------------------------
  4664.  
  4665. SOM_Scope ODID  SOMLINK CMDraftStrongClone(CMDraft *somSelf, Environment *ev,
  4666.         ODDraftKey key,
  4667.         ODID fromID,
  4668.         ODID toObjectID,
  4669.         ODID scopeID)
  4670. {
  4671.     SOM_CATCH return 0;
  4672.     
  4673.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4674.     CMDraftMethodDebug("CMDraft","StrongClone");
  4675.  
  4676. #ifdef DebugClone
  4677.     somPrintf("CMDraftStrongClone from ID %d to ID %d scope ID %d\n", fromID, toObjectID, scopeID);
  4678. #endif
  4679.  
  4680.     ODStorageUnitID        toID = 0;
  4681.     TempODStorageUnit toSU = kODNULL;
  4682.     
  4683.     _fClonedSUIDs->GetValue(&fromID, &toID);
  4684.     if (toID == 0) {
  4685.         _fWeakClonedSUIDs->GetValue(&fromID, &toID);
  4686.         if (toID == 0) {
  4687.             if (toObjectID != 0) 
  4688.                 toSU = _fDestDraft->AcquireStorageUnit(ev, toObjectID);
  4689.             else
  4690.                 toSU = _fDestDraft->CreateStorageUnit(ev);
  4691.             toID = toSU->GetID(ev);
  4692.             _fClonedSUIDs->ReplaceEntry(&fromID, &toID);
  4693.         }
  4694.         else {
  4695.             if ((toObjectID != 0) && (toObjectID != toID))
  4696.                 THROW(kODErrInvalidID);
  4697.             _fWeakClonedSUIDs->RemoveEntry(&fromID);
  4698.             _fClonedSUIDs->ReplaceEntry(&fromID, &toID);
  4699.             toSU = _fDestDraft->AcquireStorageUnit(ev, toID);
  4700.         }
  4701.     }
  4702.     else {
  4703.         if ((toObjectID != 0) && (toObjectID != toID))
  4704.             THROW(kODErrInvalidID);
  4705.         toSU = _fDestDraft->AcquireStorageUnit(ev, toID);
  4706.     }
  4707.         
  4708.     ODPersistentObject *fromObject = somSelf->RetrievePersistentObject(ev, fromID);
  4709.     if ( fromObject ) {
  4710.         TempODRefCntObject tempFromObject = fromObject; // so it gets released
  4711.         TempODFrame scopeFrame = kODNULL;
  4712.         if (scopeID != 0)
  4713.             scopeFrame = somSelf->AcquireFrame(ev, scopeID);
  4714.         fromObject->CloneInto(ev, key, toSU, scopeFrame);
  4715.         ODStorageUnit* fromSU = fromObject->GetStorageUnit(ev);
  4716.         if (fromSU != kODNULL)
  4717.             CopyDraftAnnotations(ev, fromSU, toSU);
  4718.     }
  4719.     else {
  4720.         TempODStorageUnit fromSU = somSelf->AcquireStorageUnit(ev, fromID);
  4721.         if (fromSU != kODNULL) {
  4722.             fromSU->CloneInto(ev, key, toSU, scopeID);
  4723.             ODBoolean keepProxyProperties = (_fCloneKind == kODCloneToFile)
  4724.                                         || (_fCloneKind == kODCloneAll);
  4725.             RemoveDataInterchangeProperties(ev, toSU, keepProxyProperties);
  4726. //            CopyDraftAnnotations(ev, fromSU, toSU);
  4727.         }
  4728.     }
  4729.     
  4730. #ifdef DebugClone
  4731.     somPrintf("Done CMDraftStrongClone from ID %d to ID %d\n", fromID, toID);
  4732. #endif
  4733.  
  4734.     return toID;
  4735. }        
  4736.  
  4737. //------------------------------------------------------------------------------
  4738. // CMDraft: WeakClone
  4739. //------------------------------------------------------------------------------
  4740.  
  4741. SOM_Scope ODID  SOMLINK CMDraftWeakClone(CMDraft *somSelf, Environment *ev,
  4742.         ODDraftKey key,
  4743.         ODID fromID,
  4744.         ODID toObjectID,
  4745.         ODID scopeID)
  4746. {
  4747.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4748.     CMDraftMethodDebug("CMDraft","Clone");
  4749.  
  4750.     ODUnused(scopeID);
  4751.  
  4752.     SOM_CATCH return 0;
  4753.  
  4754.     ODStorageUnitID    toID = 0;
  4755.     
  4756.     _fClonedSUIDs->GetValue(&fromID, &toID);
  4757.     if (toID == 0)
  4758.     {
  4759.         _fWeakClonedSUIDs->GetValue(&fromID, &toID);
  4760.         if (toID == 0)
  4761.         {
  4762.             toID = toObjectID;
  4763.             if ( toID == 0 )
  4764.             {
  4765.                 // Note that this may substitute the null object id, which
  4766.                 // will be returned instead of a valid object id!
  4767.                 toID = somSelf->DoWeakClone(ev, fromID);
  4768.             }
  4769.         }
  4770.     }
  4771.     if ((toObjectID != 0) && (toObjectID != toID))
  4772.         THROW(kODErrInvalidID);
  4773.     
  4774.     return toID;
  4775. }
  4776.  
  4777. //------------------------------------------------------------------------------
  4778. // CMDraft: IsValidDraftKey
  4779. //------------------------------------------------------------------------------
  4780.  
  4781. SOM_Scope ODBoolean  SOMLINK CMDraftIsValidDraftKey(CMDraft *somSelf, Environment *ev,
  4782.         ODDraftKey key)
  4783. {
  4784.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4785.     CMDraftMethodDebug("CMDraft","IsValidDraftKey");
  4786.  
  4787.     return ((key != kODNULLKey) && (_fCurrentKey == key) ? kODTrue : kODFalse);
  4788. }
  4789.  
  4790. //------------------------------------------------------------------------------
  4791. // CopyProperty
  4792. //------------------------------------------------------------------------------
  4793.  
  4794. static void CopyProperty(Environment *ev, ODStorageUnit* fromSU, ODStorageUnit* toSU, ODPropertyName prop)
  4795. {
  4796.     // Assuming fromSU is focused to prop.    
  4797.     // Copy all values into toSU, overwriting any existing values there.
  4798.  
  4799.     PreserveFocus fromFocus(ev, fromSU);
  4800.     PreserveFocus toFocus(ev, toSU);
  4801.     
  4802.     ODULong            numValues;
  4803.     ODULong            j;
  4804.     ODValueType        valueName;
  4805.  
  4806.     fromSU->Focus(ev, (ODPropertyName) prop, kODPosUndefined, kODNULL, 0, kODPosAll);
  4807.  
  4808.     numValues = fromSU->CountValues(ev);    
  4809.     
  4810.     if ( numValues > 0)
  4811.         ODSUForceFocus(ev, toSU, prop, kODNULL);
  4812.     
  4813.     for (j = 0; j < numValues; j++)
  4814.     {
  4815.         fromSU->Focus(ev, (ODPropertyName) kODNULL, kODPosSame, kODNULL, 0, kODPosNextSib);
  4816.  
  4817.         valueName = fromSU->GetType(ev);
  4818.  
  4819.         ODSUForceFocus(ev, toSU, prop, valueName);
  4820.         ODULong toSize = toSU->GetSize(ev);
  4821.         toSU->DeleteValue(ev, toSize);
  4822.  
  4823.         ODDisposePtr(valueName);
  4824.         
  4825.         ODULong size = fromSU->GetSize(ev);
  4826.         ODPtr buffer = ODNewPtr(size);
  4827.         StorageUnitGetValue(fromSU, ev, size, (ODValue) buffer);
  4828.         StorageUnitSetValue(toSU, ev, size, (ODValue) buffer);
  4829.         ODDisposePtr(buffer);
  4830.     }
  4831. }
  4832.  
  4833. //------------------------------------------------------------------------------
  4834. // CopyDraftAnnotations
  4835. //------------------------------------------------------------------------------
  4836.  
  4837. static void CopyDraftAnnotations(Environment *ev, ODStorageUnit* fromSU, ODStorageUnit* toSU)
  4838. {
  4839.     ODULong annotationPrefixLength = ODISOStrLength(kODPropPreAnnotation);
  4840.     ODULong metaDataPrefixLength = ODISOStrLength(kODPropPreODMetaData);
  4841.     
  4842.     fromSU->Focus(ev, (ODPropertyName) kODNULL, 
  4843.                             kODPosAll,
  4844.                             kODTypeAll,
  4845.                             0,
  4846.                             kODPosUndefined);
  4847.     ODULong numProperties = fromSU->CountProperties(ev);
  4848.     for (ODULong i = 1; i <= numProperties; i++) {
  4849.         fromSU->Focus(ev, (ODPropertyName) kODNULL,
  4850.                         kODPosNextSib,
  4851.                         kODTypeAll,
  4852.                         0,
  4853.                         kODPosUndefined);
  4854.         ODPropertyName propertyName = fromSU->GetProperty(ev);
  4855.         if (ODISOStrNCompare(propertyName, kODPropPreAnnotation, annotationPrefixLength) == 0)
  4856.             CopyProperty(ev, fromSU, toSU, propertyName);
  4857.         else if ((ODISOStrNCompare(propertyName, kODPropPreODMetaData, metaDataPrefixLength) == 0) &&
  4858.             (toSU->Exists(ev, propertyName, kODNULL, 0) == kODFalse)) {
  4859. #ifdef ODDebug_CloningAnnotations
  4860.             SetOutputMode(kWriteToFile);
  4861.             PRINT("metadata property %s does not exist in destination su.\n", propertyName);
  4862. #endif
  4863.             CopyProperty(ev, fromSU, toSU, propertyName);
  4864.         }
  4865.         ODDisposePtr(propertyName);
  4866.     }
  4867.  
  4868.     // Force copying of storage unit type property, which always exists so is
  4869.     // not copied in the iteration above.
  4870.     CopyProperty(ev, fromSU, toSU, kODPropStorageUnitType);
  4871. }
  4872.  
  4873. //------------------------------------------------------------------------------
  4874. // IsLinkObject
  4875. //------------------------------------------------------------------------------
  4876.  
  4877. static ODBoolean IsLinkObject(Environment* ev, ODDraft* draft, ODID objectID)
  4878. {
  4879.     // Only link objects contain a kODPropLinkSource property
  4880.  
  4881.     FN_CATCH return kODFalse;
  4882.  
  4883.     TempODStorageUnit su = draft->AcquireStorageUnit(ev, objectID);
  4884.     ODBoolean isLink = su->Exists(ev, kODPropLinkSource, kODNULL, 0);
  4885.  
  4886. #ifdef DebugClone
  4887.     if ( isLink )
  4888.         somPrintf("Object ID %d is a link\n", objectID);
  4889. #endif
  4890.     
  4891.     return isLink;
  4892. }
  4893.  
  4894. //------------------------------------------------------------------------------
  4895. // IsLinkSourceObject
  4896. //------------------------------------------------------------------------------
  4897.  
  4898. static ODBoolean IsLinkSourceObject(Environment* ev, ODDraft* draft, ODID objectID)
  4899. {
  4900.     // Only link source objects contain a kODPropLink property
  4901.  
  4902.     FN_CATCH return kODFalse;
  4903.  
  4904.     TempODStorageUnit su = draft->AcquireStorageUnit(ev, objectID);
  4905.     ODBoolean isLinkSource = su->Exists(ev, kODPropLink, kODNULL, 0);
  4906.  
  4907. #ifdef DebugClone
  4908.     if ( isLinkSource )
  4909.         somPrintf("Object ID %d is a link source\n", objectID);
  4910. #endif
  4911.     
  4912.     return isLinkSource;
  4913. }
  4914.  
  4915. //------------------------------------------------------------------------------
  4916. // IsEitherLinkObject
  4917. //------------------------------------------------------------------------------
  4918.  
  4919. static ODBoolean IsEitherLinkObject(Environment* ev, ODDraft* draft, ODID objectID)
  4920. {
  4921.     if ( IsLinkObject(ev, draft, objectID) )
  4922.         return kODTrue;
  4923.     else
  4924.         return IsLinkSourceObject(ev, draft, objectID);
  4925. }
  4926.  
  4927. //------------------------------------------------------------------------------
  4928. // IsNeitherLinkObject
  4929. //------------------------------------------------------------------------------
  4930.  
  4931. static ODBoolean IsNeitherLinkObject(Environment* ev, ODDraft* draft, ODID objectID)
  4932. {
  4933.     if ( IsLinkObject(ev, draft, objectID) )
  4934.         return kODFalse;
  4935.     else
  4936.         return !IsLinkSourceObject(ev, draft, objectID);
  4937. }
  4938.  
  4939. //------------------------------------------------------------------------------
  4940. // SetStorageUnitType
  4941. //------------------------------------------------------------------------------
  4942.  
  4943. static void SetStorageUnitType(Environment* ev, ODDraftPermissions perms, ODStorageUnit* su, ODType suType)
  4944. {    
  4945.     if (perms == kODDPExclusiveWrite)
  4946.     {
  4947.         TempODType curType = ODGetISOStrProp(ev, su, kODPropStorageUnitType, kODISOStr, kODNULL, kODNULL);
  4948.         if (!curType || !ODISOStrEqual(curType, suType))
  4949.             ODSetISOStrProp(ev, su, kODPropStorageUnitType, kODISOStr, suType);
  4950.     }
  4951. }
  4952.  
  4953. //------------------------------------------------------------------------------
  4954. // GetStorageUnitType
  4955. //------------------------------------------------------------------------------
  4956.  
  4957. static ODISOStr GetStorageUnitType(Environment* ev, ODDraft* draft, ODID objectID)
  4958. {
  4959.     FN_CATCH return kODNULL;
  4960.  
  4961.     TempODStorageUnit su = draft->AcquireStorageUnit(ev, objectID);
  4962.     PreserveFocus fromFocus(ev, su);
  4963.  
  4964.     return ODGetISOStrProp(ev, su, kODPropStorageUnitType, kODISOStr, kODNULL, kODNULL);
  4965. }
  4966.  
  4967. //------------------------------------------------------------------------------
  4968. // RootPartID
  4969. //------------------------------------------------------------------------------
  4970.  
  4971. static ODID RootPartID(Environment* ev, ODDraft* draft)
  4972. {
  4973.     TempODStorageUnit draftProperties = draft->AcquireDraftProperties(ev);
  4974.     return ODGetStrongSURefProp(ev, draftProperties, kODPropRootPartSU, kODStrongStorageUnitRef);
  4975. }
  4976.  
  4977. //------------------------------------------------------------------------------
  4978. // CheckClonedObject
  4979. //------------------------------------------------------------------------------
  4980.  
  4981. SOM_Scope void  SOMLINK CMDraftCheckClonedObject(CMDraft *somSelf, Environment *ev,
  4982.         ODID fromID,
  4983.         ODID toID,
  4984.         ODID originalID)
  4985. {
  4986.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4987.     CMDraftMethodDebug("CMDraft","CheckClonedObject");
  4988.     
  4989.     ODISOStr storageUnitType = kODNULL; ODVolatile(storageUnitType);
  4990.     
  4991.     SOM_TRY
  4992.     
  4993.     storageUnitType = GetStorageUnitType(ev, somSelf, fromID);
  4994.     
  4995. #ifdef DebugClone
  4996.     somPrintf("CheckClonedObject: Type is %s\n", storageUnitType);
  4997. #endif
  4998.    
  4999.     if ( ODISOStrEqual(kODFrameObject, storageUnitType) )
  5000.     {
  5001.         _fAnyFrameCloned = kODTrue;
  5002.     }
  5003.     else if ( ODISOStrEqual(kODPartObject, storageUnitType) )
  5004.     {
  5005.         if ( (toID == originalID) && (RootPartID(ev, somSelf) == fromID) )
  5006.         {
  5007.             _fRootPartReused = kODTrue;
  5008. #ifdef DebugClone
  5009.             somPrintf("CheckClonedObject: Root part reused\n");
  5010. #endif
  5011.         }
  5012.     }
  5013.  
  5014.     SOM_CATCH_ALL
  5015.     SOM_ENDTRY
  5016.  
  5017.     ODDisposePtr(storageUnitType);
  5018. }
  5019.  
  5020. //------------------------------------------------------------------------------
  5021. // SetOriginalDraft
  5022. //------------------------------------------------------------------------------
  5023.  
  5024. static void SetOriginalDraft(Environment* ev, ODDraft* targetDraft, ODDraft* originalDraft)
  5025. {
  5026.     TempODStorageUnit draftProperties = targetDraft->AcquireDraftProperties(ev);
  5027.     ODSetULongProp(ev, draftProperties, kODPropOriginalDraft, kODULong, (ODULong) originalDraft);
  5028. }
  5029.  
  5030. //------------------------------------------------------------------------------
  5031. // GetOriginalDraft
  5032. //------------------------------------------------------------------------------
  5033. // Returns kODNULL if the original draft is unknown.  This is the case when content
  5034. // was placed in the draft without cloning.
  5035.  
  5036. static ODDraft* GetOriginalDraft(Environment* ev, ODDraft* draft)
  5037. {
  5038.     TempODStorageUnit    draftProperties = draft->AcquireDraftProperties(ev);
  5039.     return (ODDraft*)ODGetULongProp(ev, draftProperties, kODPropOriginalDraft, kODULong);
  5040. }
  5041.  
  5042. //------------------------------------------------------------------------------
  5043. // OriginalCloneKindExists
  5044. //------------------------------------------------------------------------------
  5045.  
  5046. static ODBoolean OriginalCloneKindExists(Environment* ev, ODDraft* draft)
  5047. {
  5048.     TempODStorageUnit draftProperties = draft->AcquireDraftProperties(ev);
  5049.     return draftProperties->Exists(ev, kODPropOriginalCloneKind, kODULong, 0);
  5050. }
  5051.  
  5052. //------------------------------------------------------------------------------
  5053. // SetOriginalCloneKind
  5054. //------------------------------------------------------------------------------
  5055.  
  5056. static void SetOriginalCloneKind(Environment* ev, ODDraft* targetDraft, ODCloneKind cloneKind)
  5057. {
  5058.     TempODStorageUnit draftProperties = targetDraft->AcquireDraftProperties(ev);
  5059.     ODSetULongProp(ev, draftProperties, kODPropOriginalCloneKind, kODULong, (ODULong) cloneKind);
  5060. }
  5061.  
  5062. //------------------------------------------------------------------------------
  5063. // CMDraft: GetHeap
  5064. //------------------------------------------------------------------------------
  5065.  
  5066. SOM_Scope ODMemoryHeapID  SOMLINK CMDraftGetHeap(CMDraft *somSelf, Environment *ev)
  5067. {
  5068.     CMDraftData *somThis = CMDraftGetData(somSelf);
  5069.     CMDraftMethodDebug("CMDraft","GetHeap");
  5070.  
  5071.     return _fHeap;
  5072. }
  5073.  
  5074. //------------------------------------------------------------------------------
  5075. // CMDraft: CreateLinkIterator
  5076. //------------------------------------------------------------------------------
  5077.  
  5078. SOM_Scope ODLinkIterator*  SOMLINK CMDraftCreateLinkIterator(CMDraft *somSelf, Environment *ev)
  5079. {
  5080.     CMDraftData *somThis = CMDraftGetData(somSelf);
  5081.     CMDraftMethodDebug("CMDraft","CreateLinkIterator");
  5082.  
  5083.     CMLinkIterator* iter = kODNULL;
  5084.     ODVolatile(iter);
  5085.     SOM_TRY
  5086.     
  5087.         iter = new CMLinkIterator();
  5088.         THROW_IF_NULL(iter, kODErrOutOfMemory);
  5089.         iter->InitCMLinkIterator(ev, somSelf);
  5090.     
  5091.     SOM_CATCH_ALL
  5092.         
  5093.         ODDeleteObject(iter);
  5094.     
  5095.     SOM_ENDTRY
  5096.     
  5097.     return (ODLinkIterator*) iter;
  5098. }
  5099.  
  5100. //------------------------------------------------------------------------------
  5101. // CMDraft: CreateLinkSourceIterator
  5102. //------------------------------------------------------------------------------
  5103.  
  5104. SOM_Scope ODLinkSourceIterator*  SOMLINK CMDraftCreateLinkSourceIterator(CMDraft *somSelf, Environment *ev)
  5105. {
  5106.     CMDraftData *somThis = CMDraftGetData(somSelf);
  5107.     CMDraftMethodDebug("CMDraft","CreateLinkSourceIterator");
  5108.  
  5109.     CMLinkSourceIterator* iter  = kODNULL;
  5110.     ODVolatile(iter);
  5111.     SOM_TRY
  5112.     
  5113.         iter = new CMLinkSourceIterator();
  5114.         THROW_IF_NULL(iter, kODErrOutOfMemory);
  5115.         iter->InitCMLinkSourceIterator(ev, somSelf);
  5116.         
  5117.     SOM_CATCH_ALL
  5118.         
  5119.         ODDeleteObject(iter);
  5120.     
  5121.     SOM_ENDTRY
  5122.     
  5123.     return (ODLinkSourceIterator*) iter;
  5124. }
  5125.  
  5126. //------------------------------------------------------------------------------
  5127. // itoa
  5128. //------------------------------------------------------------------------------
  5129. static void itoa(ODULong number, ODSByte* cstring)
  5130. {
  5131.     ODULong    i = 0;
  5132.     
  5133.     do {
  5134.         cstring[i++] = (ODSByte) (number % 10 + '0');
  5135.     } while ((number /= 10) > 0);
  5136.     cstring[i] = '\0';
  5137.  
  5138.     ODSByte    c;
  5139.     
  5140.     ODULong    j;
  5141.     
  5142.     for (i = 0, j = strlen(cstring)-1; i < j;i++, j--) {
  5143.         c = cstring[i];
  5144.         cstring[i] = cstring[j];
  5145.         cstring[j] = c;
  5146.     }
  5147. }
  5148.  
  5149. //------------------------------------------------------------------------------
  5150. // NewCMStorageUnit
  5151. //------------------------------------------------------------------------------
  5152.  
  5153. static CMStorageUnit* NewCMStorageUnit(ODMemoryHeapID heapID)
  5154. {
  5155.     SOMClass*    cmStorageUnitClass = somNewClassReference(CMStorageUnit);
  5156.     ODULong        size = cmStorageUnitClass->somGetInstanceSize();
  5157.     ODPtr        buffer = ODNewPtr(size, heapID);
  5158.     CMStorageUnit*    cmStorageUnit = (CMStorageUnit*) cmStorageUnitClass->somRenew(buffer);
  5159.     somReleaseClassReference ( cmStorageUnitClass );
  5160.     
  5161.     return cmStorageUnit;
  5162. }
  5163.  
  5164. //------------------------------------------------------------------------------
  5165. // PurgeAllStorageUnits
  5166. //------------------------------------------------------------------------------
  5167.  
  5168. static ODULong PurgeAllStorageUnits(Environment* ev, OpenHashTable* storageUnits, IDList* idList)
  5169. {
  5170.     ODID                    id;
  5171.     ODStorageUnit*            su;
  5172.     ODULong                    runningTotal = 0;
  5173.  
  5174. // idList is used to indicate whether we need to remove linkage between id and cmObject
  5175.  
  5176.     OpenHashTableIterator    suIter(storageUnits);
  5177.     for (suIter.First(&id, &su); suIter.IsNotComplete(); suIter.Next(&id, &su)) {
  5178.         if (su->GetRefCount(ev) != 0) {
  5179.             if (idList) // purge should release CMObject, signal that by removing from idList
  5180.                 idList->Remove(id); 
  5181.             runningTotal += su->Purge(ev, 0);
  5182.         }
  5183.     }
  5184. /*
  5185.     for (suIter.First(&id, &su); suIter.IsNotComplete(); suIter.Next(&id, &su)) {
  5186.         if (su->GetRefCount(ev) == 0) {
  5187.             suIter.RemoveCurrent();
  5188.             delete su;
  5189.         }
  5190.     }
  5191. */
  5192.     // ShrinkToFit() allocates new tables first, and this aggravates
  5193.     // low memory conditions during Purge().
  5194.     // storageUnits->ShrinkToFit(/*extraSlots*/ 0);
  5195.         
  5196.     return runningTotal;
  5197. }
  5198.  
  5199. //------------------------------------------------------------------------------
  5200. // CMDraft: PartInstantiated
  5201. //------------------------------------------------------------------------------
  5202.  
  5203. SOM_Scope void  SOMLINK CMDraftPartInstantiated(CMDraft *somSelf, Environment *ev,
  5204.         ODPart* realPart)
  5205. {
  5206.     CMDraftData *somThis = CMDraftGetData(somSelf);
  5207.     CMDraftMethodDebug("CMDraft","PartInstantiated");
  5208. }
  5209.  
  5210. //------------------------------------------------------------------------------
  5211. // CMDraft: PartDeleted
  5212. //------------------------------------------------------------------------------
  5213.  
  5214. SOM_Scope void  SOMLINK CMDraftPartDeleted(CMDraft *somSelf, Environment *ev,
  5215.         ODPart* realPart)
  5216. {
  5217.     CMDraftData *somThis = CMDraftGetData(somSelf);
  5218.     CMDraftMethodDebug("CMDraft","PartDeleted");
  5219. }
  5220.  
  5221. //------------------------------------------------------------------------------
  5222. // CMDraft: SwapPart
  5223. //------------------------------------------------------------------------------
  5224.  
  5225. SOM_Scope void  SOMLINK CMDraftSwapPart(CMDraft *somSelf, Environment *ev,
  5226.         ODPart* part)
  5227. {
  5228.     CMDraftData *somThis = CMDraftGetData(somSelf);
  5229.     CMDraftMethodDebug("CMDraft","SwapPart");
  5230.  
  5231.     SOM_TRY
  5232.         OpenHashTableIterator     i(_fPersistentObjects);
  5233.         ODStorageUnitID            id;
  5234.         ODPersistentObject*        object;
  5235.         ODFrame*                frame;
  5236.  
  5237.         somSelf->Externalize(ev);
  5238.         
  5239.         for (i.First(&id, &object); i.IsNotComplete(); i.Next(&id, &object)) {
  5240.             if ( strcmp(object->somGetClassName(), kFrameClassName)==0 ) {
  5241.                 frame = (ODFrame*)object;
  5242.                 if ( frame->IsSubframe(ev) == kODFalse )
  5243.                     frame->PrepareToSwap(ev, part);
  5244.             }
  5245.         }
  5246.     SOM_CATCH_ALL
  5247.     SOM_ENDTRY
  5248. }
  5249.